Opencv 学习---8种常用图像增强算法
常見的8種圖像增強算法及其opencv實現
1.直方圖均衡化
? ? ? ?直方圖均衡化是圖像處理領域中利用圖像直方圖對對比度進行調整的方法。?
這種方法通常用來增加許多圖像的局部對比度。這種方法對于背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來X光圖像中更好的骨骼結構顯示以及曝光過度或者曝光不足照片中更好的細節。這種方法的一個主要優勢是它是一個相當直觀的技術并且是可逆操作。
? ? ? ?參考來源 openCV直方圖均衡化https://blog.csdn.net/zhangfuliang123/article/details/74170894
? ? ? 首先openCV沒有直方圖直接顯示的函數,所以我們需要創建直方圖來自定義繪圖,函數如下:
/*
?? ? width:直方圖寬度 ? ? height:直方圖高度 ? ? scale:
*/
IplImage* showImageHistogram(IplImage** image, int width, int height ,int scale){
?
?? ?int dims = 1;
?? ?int histSize = 256;
?? ?float frange[] = { 0, 255 };
?? ?float* ranges[] = { frange };
?? ?//創建一個直方圖 ? ? CV_HIST_ARRAY多維密集數組
?? ?CvHistogram* ?hist = cvCreateHist(dims, &histSize, CV_HIST_ARRAY, ranges);
?? ?//根據輸入圖像計算直方圖
?? ?cvCalcHist(image, hist);
?
?
?? ?//繪制直方圖區域
?? ?IplImage* histImage = cvCreateImage(cvSize(width*scale, height), IPL_DEPTH_8U, 1);
?? ?//直方圖背景區域置位白色
?? ?cvRectangle(histImage, cvPoint(0, 0), cvPoint(histImage->width, histImage->height), CV_RGB(255,255,255), CV_FILLED);
?? ?//獲取最大值
?? ?float maxHistValue = 0;
?? ?cvGetMinMaxHistValue(hist, NULL, &maxHistValue, NULL,NULL);
?? ?//繪制各個灰度級的直方圖
?? ?for (int i = 0; i < width; i++){
?? ??? ?float value = cvQueryHistValue_1D(hist, i);
?? ??? ?int drawHeight = cvRound((value / maxHistValue) * height);
?? ??? ?cvRectangle(histImage, cvPoint(i*scale, height-1), cvPoint((i+1)*scale -1, height-drawHeight), cvScalar(i, 0, 0, 0), CV_FILLED);
?? ?}
?? ?return histImage;
?
}
直接處理灰度圖:
- 使用OpenCV函數?EqualizeHist?對直方圖均衡化
void histGrayChange(){
?? ?const char* picName = "test.tif";//test.tif lenaRGB.tif
?? ?//采用IplImage *img = cvLoadImage(picName)默認值是CV_LOAD_IMAGE_COLOR ?讀取無論原始圖像的通道數是多少,都將被轉換為3個通道讀入。
?? ?//IplImage *img = cvLoadImage(picName);
?
?? ?//******以灰度圖像讀入,強制轉換為單通道*****
?? ?IplImage *img = cvLoadImage(picName,CV_LOAD_IMAGE_GRAYSCALE);
?? ?if (img == NULL){
?? ??? ?cout << "Load File Failed." << endl;
?? ?}
?? ?cout << "ChannelL:" << img->nChannels;
?
?
?? ?IplImage* imgDst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
?? ?//直方圖均衡化
?? ?cvEqualizeHist(img, imgDst);
?? ?
?? ?cvNamedWindow("Origin", CV_WINDOW_AUTOSIZE);
?? ?cvShowImage("Origin", img);
?
?? ?cvNamedWindow("Result", CV_WINDOW_AUTOSIZE);
?? ?cvShowImage("Result", imgDst);
?
?? ?//
?? ?int histImageWidth = 255;
?? ?int histImageHeight = 150;
?? ?int histImageScale = 2;
?? ?IplImage *histImage1 = showImageHistogram(&img, histImageWidth, histImageHeight, histImageScale);
?? ?cvNamedWindow("Hist1", CV_WINDOW_AUTOSIZE);
?? ?cvShowImage("Hist1", histImage1);
?
?? ?IplImage *histImage2 = showImageHistogram(&imgDst, histImageWidth, histImageHeight, histImageScale);
?? ?cvNamedWindow("Hist2", CV_WINDOW_AUTOSIZE);
?? ?cvShowImage("Hist2", histImage2);
?
?
?? ?cvWaitKey();
?
?? ?cvDestroyWindow("Origin"); cvReleaseImage(&img);
?? ?cvDestroyWindow("Result"); cvReleaseImage(&imgDst);
?
}
?
也可以實現對彩色圖片的直方圖均衡化,代碼就在前面的鏈接里,不貼了。
?
2、對數圖像增強算法
? ? ? 對數圖像增強是圖像增強的一種常見方法,其公式為: S = c log(r+1),其中c是常數(以下算法c=255/(log(256)),這樣可以實現整個畫面的亮度增大。
void LogEnhance(IplImage* img, IplImage* dst)
{
?? ?// 由于oldPixel:[1,256],則可以先保存一個查找表
?? ?uchar lut[256] ={0};
?
?? ?double temp = 255/log(256);
?
?? ?for ( int i =0; i<255; i++)
?? ?{
?? ??? ?lut[i] = (uchar)(temp* log(i+1)+0.5);
?? ?}
?
?? ?for( int row =0; row <img->height; row++)
?? ?{
?? ??? ?uchar *data = (uchar*)img->imageData+ row* img->widthStep;
?? ??? ?uchar *dstData = (uchar*)dst->imageData+ row* dst->widthStep;
?
?? ??? ?for ( int col = 0; col<img->width; col++)
?? ??? ?{
?? ??? ??? ?for( int k=0; k<img->nChannels; k++)
?? ??? ??? ?{
?? ??? ??? ??? ?uchar t1 = data[col*img->nChannels+k];?? ??? ??? ??? ?
?? ??? ??? ??? ?dstData[col*img->nChannels+k] = lut[t1];
?? ??? ??? ?}
?? ??? ?}?? ??? ?
?? ?}?? ?
}
3、指數圖像增強算法
?
? ? ? 指數圖像增強的表達為:S = cR^r,通過合理的選擇c和r可以壓縮灰度范圍,算法以c=1.0/255.0, r=2實現。
void ExpEnhance(IplImage* img, IplImage* dst)
{
?? ?// 由于oldPixel:[1,256],則可以先保存一個查找表
?? ?uchar lut[256] ={0};
?
?? ?double temp = 1.0/255.0;
?
?? ?for ( int i =0; i<255; i++)
?? ?{
?? ??? ?lut[i] = (uchar)(temp*i*i+0.5);
?? ?}
?
?? ?for( int row =0; row <img->height; row++)
?? ?{
?? ??? ?uchar *data = (uchar*)img->imageData+ row* img->widthStep;
?? ??? ?uchar *dstData = (uchar*)dst->imageData+ row* dst->widthStep;
?
?? ??? ?for ( int col = 0; col<img->width; col++)
?? ??? ?{
?? ??? ??? ?for( int k=0; k<img->nChannels; k++)
?? ??? ??? ?{
?? ??? ??? ??? ?uchar t1 = data[col*img->nChannels+k];?? ??? ??? ??? ?
?? ??? ??? ??? ?dstData[col*img->nChannels+k] = lut[t1];
?? ??? ??? ?}
?? ??? ?}?? ??? ?
?? ?}?? ?
}
?
4、加Masaic算法(馬賽克)
?
? ? ? ? 在日常中有時候保密或其他需要將圖像馬賽克,下面的算法實現圖像馬賽克功能(原理:用中心像素來表示鄰域像素)。
?
uchar getPixel( IplImage* img, int row, int col, int k) {return ((uchar*)img->imageData + row* img->widthStep)[col*img->nChannels +k]; }void setPixel( IplImage* img, int row, int col, int k, uchar val) {((uchar*)img->imageData + row* img->widthStep)[col*img->nChannels +k] = val; }// nSize:為尺寸大小,奇數
// 將鄰域的值用中心像素的值替換
void Masic(IplImage* img, IplImage* dst, int nSize)
{
?? ?int offset = (nSize-1)/2;
?? ?for ( int row = offset; row <img->height - offset; row= row+offset)
?? ?{
?? ??? ?for( int col= offset; col<img->width - offset; col = col+offset)
?? ??? ?{
?? ??? ??? ?int val0 = getPixel(img, row, col, 0);
?? ??? ??? ?int val1 = getPixel(img, row, col, 1);
?? ??? ??? ?int val2 = getPixel(img, row, col, 2);
?? ??? ??? ?for ( int m= -offset; m<offset; m++)
?? ??? ??? ?{
?? ??? ??? ??? ?for ( int n=-offset; n<offset; n++)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?setPixel(dst, row+m, col+n, 0, val0);
?? ??? ??? ??? ??? ?setPixel(dst, row+m, col+n, 1, val1);
?? ??? ??? ??? ??? ?setPixel(dst, row+m, col+n, 2, val2);
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ?}
}
?
5、曝光過度問題處理
?
? ? ? 對于曝光過度問題,可以通過計算當前圖像的反相(255-image),然后取當前圖像和反相圖像的較小者為當前像素位置的值。
// 過度曝光原理:圖像翻轉,然后求原圖與反圖的最小值
void ExporeOver(IplImage* img, IplImage* dst)
{
?? ?for( int row =0; row <img->height; row++)
?? ?{
?? ??? ?uchar *data = (uchar*)img->imageData+ row* img->widthStep;
?? ??? ?uchar *dstData = (uchar*)dst->imageData+ row* dst->widthStep;
?
?? ??? ?for ( int col = 0; col<img->width; col++)
?? ??? ?{
?? ??? ??? ?for( int k=0; k<img->nChannels; k++)
?? ??? ??? ?{
?? ??? ??? ??? ?uchar t1 = data[col*img->nChannels+k];
?? ??? ??? ??? ?uchar t2 = 255 - t1;
?? ??? ??? ??? ?dstData[col*img->nChannels+k] = min(t1,t2);
?? ??? ??? ?}
?? ??? ?}?? ??? ?
?? ?}
}
?
6、高反差保留
? ? ? 高反差保留主要是將圖像中顏色、明暗反差較大兩部分的交界處保留下來,比如圖像中有一個人和一塊石頭,那么石頭的輪廓線和人的輪廓線以及面部、服裝等有明顯線條的地方會變被保留,兒其他大面積無明顯明暗變化的地方則生成中灰色。其表達形式為:dst = r*(img - Blur(img))。
?
Mat HighPass(Mat img) {Mat temp;GaussianBlur(img, temp,Size(7,7),1.6,1.6);int r=3;?? ?Mat diff = img + r*(img-temp); //高反差保留算法return diff; }測試代碼:
int main(int argc, char* argv[]) {const char* Path = "02.bmp";IplImage *img = cvLoadImage(Path,CV_LOAD_IMAGE_ANYCOLOR);IplImage *dst = cvCreateImage(cvGetSize(img), img->depth, img->nChannels);cout<<"輸入你要選擇的操作:"<<endl;cout<<"1、曝光過度"<<endl;cout<<"2、加馬賽克"<<endl;cout<<"3、對數增強"<<endl;cout<<"4、指數增強"<<endl;cout<<"請輸入你的選擇:";int choice = 1;cin>>choice;switch (choice){case 1:?ExporeOver(img, dst); ? //這四個算法中總覺得某個算法有問題break;case 2:?Masic(img, dst, 21);break;case 3:?LogEnhance(img, dst);break;case 4:ExpEnhance(img, dst);break;default:cout<<"輸入錯誤"<<endl;break;?? ??? ??? ? ?}cvSaveImage("dst.jpg",dst);cvNamedWindow("SRC",1);cvNamedWindow("DST", 1);cvShowImage("SRC", img);cvShowImage("DST", dst);cvWaitKey();return 0; }7.拉普拉斯算子圖像增強
使用中心為5的8鄰域拉普拉斯算子與圖像卷積可以達到銳化增強圖像的目的。
拉普拉斯算子增強局部的圖像對比度的opencv代碼:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
?
using namespace cv;
?
int main(int argc, char *argv[])
{
? ? Mat image = imread("/Users/shandiangou/Downloads/lena.png");
? ? if (image.empty())
? ? {
? ? ? ? std::cout << "打開圖片失敗,請檢查" << std::endl;
? ? ? ? return -1;
? ? }
? ? imshow("原圖像", image);
? ? waitKey();
? ? Mat imageEnhance;
? ? Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, 0, 5, 0, 0, -1, 0);
? ? filter2D(image, imageEnhance, CV_8UC3, kernel);
? ? imshow("拉普拉斯算子圖像增強效果", imageEnhance);
? ? waitKey();
? ? return 0;
}
?
參考博客:直方圖均衡化、拉普拉斯算子圖像增強、Gamma校正https://blog.csdn.net/sinat_28296297/article/details/77972023
? ? ? ? ? ? ? ? ? ?OpenCV_基于Laplacian算子的圖像邊緣增強https://blog.csdn.net/icvpr/article/details/8502949
8.Gamma校正
? ? ? ?伽馬變換主要用于圖像的校正,將灰度過高或者灰度過低的圖片進行修正,增強對比度。伽馬變換對圖像的修正作用其實就是通過增強低灰度或高灰度的細節實現的。
實現代碼
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
?
#include <iostream>
?
using namespace cv;
using namespace std;
?
// Normalizes a given image into a value range between 0 and 255.
Mat norm_0_255(const Mat& src) {
? ? // Create and return normalized image:
? ? Mat dst;
? ? switch(src.channels()) {
? ? ? ? case 1:
? ? ? ? ? ? cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
? ? ? ? ? ? break;
? ? ? ? case 3:
? ? ? ? ? ? cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? src.copyTo(dst);
? ? ? ? ? ? break;
? ? }
? ? return dst;
}
?
int main(int argc, const char *argv[]) {
? ? // Get filename to the source image:
? ? // Load image & get skin proportions:
? ? Mat image = imread("/Users/shandiangou/Downloads/guobao.jpeg");
? ? // Convert to floating point:
? ? Mat X;
? ? image.convertTo(X, CV_32FC1);
? ? //image.convertTo(X, CV_32F);
? ? // Start preprocessing:
? ? Mat I;
? ? float gamma = 3;
? ? pow(X, gamma, I);
? ??
? ??
? ? // Draw it on screen:
? ? imshow("Original Image", image);
? ? waitKey();
? ? imshow("Gamma correction image", norm_0_255(I));
? ? // Show the images:
? ? waitKey();
? ? // Success!
? ? return 0; ?
}
暫時總結的就這8類,其他的之后再添
總結
以上是生活随笔為你收集整理的Opencv 学习---8种常用图像增强算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 硬件设计——MOS管实际应用详解
- 下一篇: reaxff反应力场计算