3.2直方图处理
3.2.1灰度直方图
1 //////3.2.1灰度直方图方法2: 2 ////Source Code:https://blog.csdn.net/gone_huilin/article/details/53222806 3 #include <opencv2\opencv.hpp> 4 int main() 5 { 6 // 图像源获取及判断 7 cv::Mat Image, ImageGray; 8 Image = cv::imread("D:\\lena.jpg"); 9 if (Image.empty()) 10 return -1; 11 cv::imshow("Image", Image); 12 // 转换为灰度图像 13 cv::cvtColor(Image, ImageGray, CV_BGR2GRAY); 14 // 定义直方图参数 15 const int channels[1] = { 0 }; 16 const int histSize[1] = { 256 }; 17 float pranges[2] = { 0,255 }; 18 const float* ranges[1] = { pranges }; 19 cv::MatND hist; 20 // 计算直方图 21 cv::calcHist(&ImageGray, 1, channels, cv::Mat(), hist, 1, 22 histSize, ranges); 23 // 初始化画布参数 24 int hist_w = 500; 25 int hist_h = 500; 26 int nHistSize = 255; 27 // 区间 28 int bin_w = cvRound((double)hist_w / nHistSize); 29 cv::Mat histImage(hist_w, hist_h, 30 CV_8UC3, cv::Scalar(0, 0, 0)); 31 // 将直方图归一化到范围 [ 0, histImage.rows ] 32 normalize(hist, hist, 0, histImage.rows, 33 cv::NORM_MINMAX, -1, cv::Mat()); 34 // 在直方图画布上画出直方图 35 for (int i = 1; i < nHistSize; i++) 36 { 37 line(histImage, cv::Point(bin_w*(i - 1), 38 hist_h - cvRound(hist.at<float>(i - 1))), 39 cv::Point(bin_w*(i), 40 hist_h - cvRound(hist.at<float>(i))), 41 cv::Scalar(0, 0, 255), 2, 8, 0); 42 } 43 // 显示直方图 44 cv::imshow("histImage", histImage); 45 cv::waitKey(); 46 return 0; 47 }
1 ////3.2.1灰度直方图 2 ////Source Code:https://blog.csdn.net/qq_20823641/article/details/51932798 3 #include "opencv2/highgui/highgui.hpp" 4 #include "opencv2/imgproc/imgproc.hpp" 5 #include <iostream> 6 using namespace cv; 7 using namespace std; 8 9 void Help() 10 { 11 printf("\n\n\t\t\t欢迎来到直方图的世界!\n"); 12 printf("\n\n ----------------------------------------------------------------------------\n"); 13 } 14 15 16 int main() 17 { 18 Mat srcImage = imread("D:\\lena.jpg"); 19 Mat grayImage; 20 if (!srcImage.data) 21 { 22 cout << "fail to load image" << endl; 23 return 0; 24 } 25 imshow("原图", srcImage); 26 cvtColor(srcImage, grayImage, CV_RGB2GRAY); 27 imshow("灰度图", grayImage); 28 29 system("color 1F"); 30 Help(); 31 32 MatND dstHist; // 在cv中用CvHistogram *hist = cvCreateHist 33 int dims = 1; 34 float hranges[2] = { 0, 255 }; 35 const float *ranges[1] = { hranges }; // 这里需要为const类型 36 int size = 256; 37 int channels = 0; 38 //计算图像的直方图 39 calcHist(&grayImage, 1, &channels, Mat(), dstHist, dims, &size, ranges); // cv 中是cvCalcHist 40 int scale = 1; 41 Mat dstImage(size * scale, size, CV_8U, Scalar(0)); 42 //获取最大值和最小值 43 double minValue = 0; 44 double maxValue = 0; 45 minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); // 在cv中用的是cvGetMinMaxHistValue 46 //绘制出直方图 47 int hpt = saturate_cast<int>(0.9 * size); 48 for (int i = 0; i < 256; i++) 49 { 50 float binValue = dstHist.at<float>(i); // 注意hist中是float类型 51 int realValue = saturate_cast<int>(binValue * hpt / maxValue); 52 //rectangle(dstImage,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255)); 53 line(dstImage, Point(i*scale, size - 1), Point((i + 1)*scale - 1, size - realValue), Scalar(255)); 54 } 55 imshow("一维直方图", dstImage); 56 waitKey(0); 57 return 0; 58 }
////Source Code:https://blog.csdn.net/qq_20823641/article/details/51932798 #include "cv.h" #include "highgui.h" #include <stdio.h> #include <ctype.h> #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace std; using namespace cv; IplImage *src = 0; IplImage *histimg = 0; CvHistogram *hist = 0; int hdims = 50; // 划分HIST的初始个数,越高越精确 //滚动条函数 void HIST(int t) { float hranges_arr[] = { 0,255 }; float* hranges = hranges_arr; int bin_w; int bin_u; float max; int i; char string[10]; CvFont font; cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1, 1, 0, 1, 8);//字体结构初始化 if (hdims == 0) { printf("直方图条数不能为零!\n"); } else { hist = cvCreateHist(1, &hdims, CV_HIST_ARRAY, &hranges, 1); // 创建直方图 histimg = cvCreateImage(cvSize(800, 512), 8, 3); cvZero(histimg); cvCalcHist(&src, hist, 0, 0); // 计算直方图 cvGetMinMaxHistValue(hist, NULL, &max, NULL, NULL);//寻找最大值及其位置 //printf("max_val:%f \n",max_val); cvZero(histimg); double bin_w = (double)histimg->width / hdims; // hdims: 条的个数,则 bin_w 为条的宽度 double bin_u = (double)histimg->height / max; //// max: 最高条的像素个数,则 bin_u 为单个像素的高度 // 画直方图 for (int i = 0; i<hdims; i++) { CvPoint p0 = cvPoint(i*bin_w, histimg->height); int val = cvGetReal1D(hist->bins, i); CvPoint p1 = cvPoint((i + 1)*bin_w, histimg->height - cvGetReal1D(hist->bins, i)*bin_u); cvRectangle(histimg, p0, p1, cvScalar(0, 255), 1, 8, 0); } //画纵坐标刻度(像素个数) int kedu = 0; for (int i = 1; kedu<max; i++) { kedu = i*max / 10; _itoa_s(kedu, string, 10);//把一个整数转换为字符串 //在图像中显示文本字符串 cvPutText(histimg, string, cvPoint(0, histimg->height - kedu*bin_u), &font, CV_RGB(0, 255, 255)); } //画横坐标刻度(像素灰度值) kedu = 0; for (int i = 1; kedu<256; i++) { kedu = i * 20; _itoa_s(kedu, string, 10);//把一个整数转换为字符串 //在图像中显示文本字符串 cvPutText(histimg, string, cvPoint(kedu*(histimg->width / 256), histimg->height), &font, CV_RGB(255, 0, 0)); } cvShowImage("Histogram", histimg); } } int main(int argc, char** argv) { argc = 2; argv[1] = "D:\\lena.jpg"; if (argc != 2 || (src = cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1; cvNamedWindow("src", 1); cvShowImage("src", src); cvNamedWindow("Histogram", 1); cvCreateTrackbar("hdims", "src", &hdims, 256, HIST); HIST(0); cvWaitKey(0); cvDestroyWindow("src"); cvDestroyWindow("Histogram"); cvReleaseImage(&src); cvReleaseImage(&histimg); cvReleaseHist(&hist); return 0; }
参考:
https://blog.csdn.net/xiaowei_cqu/article/details/7600666
https://www.cnblogs.com/wangguchangqing/p/7098213.html
3.2.2 H-S直方图
1 ////Source Code: https://blog.csdn.net/uestc_c2_403/article/details/72814455 2 #include "opencv2/highgui/highgui.hpp" 3 #include "opencv2/imgproc/imgproc.hpp" 4 #include "opencv2/opencv.hpp" 5 #include "opencv2/core/core.hpp" 6 #include <stdio.h> 7 #include <string> 8 using namespace std; 9 using namespace cv; 10 int main() 11 { 12 cv::Mat hsvMat; 13 cv::Mat srcImage = cv::imread("D:\\lena.jpg"); 14 15 if (srcImage.empty()) 16 { 17 return -1; 18 } 19 cv::imshow("原图像", srcImage); 20 //灰度转换 21 cv::Mat srcGray; 22 cv::cvtColor(srcImage, hsvMat, CV_BGR2HSV); 23 cv::imshow("hsvMat", hsvMat); 24 //初始化灰度阶参数 25 int hbins = 30; 26 int sbins = 32; 27 int histSize[] = { hbins, sbins }; 28 //灰度变化范围设置 29 float hranges[] = { 0, 180 }; 30 //饱和度变化范围 31 float sranges[] = { 0, 256 }; 32 const float* ranges[] = { hranges, sranges }; 33 cv::MatND hist; 34 35 //选取计算直方图通道 36 int channels[] = { 0, 1 }; 37 //计算当前通道直方图 38 cv::calcHist(&hsvMat, 1, channels, cv::Mat(), hist, 2, histSize, ranges, true, false); 39 double maxVal = 0; 40 //找到直方图最大值 41 cv::minMaxLoc(hist, 0, &maxVal, 0, 0); 42 int scale = 10; 43 cv::Mat histImage = cv::Mat::zeros(sbins*scale, hbins * scale, CV_8UC3); 44 //遍历H、S通道 45 for (int h = 0; h < hbins; h++) 46 { 47 for (int s = 0; s < sbins; s++) 48 { 49 float binVal = hist.at<float>(h, s); 50 //根据最大值计算变化范围 51 int intensity = cvRound(binVal * 255 / maxVal); 52 //绘图显示 53 cv::rectangle(histImage, cv::Point(h*scale, s*scale), 54 cv::Point((h + 1)*scale - 1, (s + 1)*scale - 1), cv::Scalar::all(intensity), CV_FILLED); 55 } 56 } 57 58 cv::imshow("H-S Histogram", histImage); 59 cv::waitKey(0); 60 return 0; 61 }
3.2.3B-G-R直方图
1 ////https://blog.csdn.net/gone_huilin/article/details/53222853 2 #include <opencv2/opencv.hpp> 3 #include <vector> 4 #include <iostream> 5 6 using namespace cv; 7 8 int main() 9 { 10 cv::Mat srcImage = cv::imread("D:\\lena.jpg"); 11 if (!srcImage.data) 12 return 1; 13 cv::imshow("srcImage", srcImage); 14 cv::Mat bgr_planes[3]; 15 cv::split(srcImage, bgr_planes); 16 17 // 初始化直方图计算参数 18 int histSize = 256; 19 float range[] = { 0, 256 }; 20 const float* histRange = { range }; 21 bool uniform = true; 22 bool accumulate = false; 23 cv::Mat b_hist, g_hist, r_hist; 24 // 计算各个通道的直方图 25 calcHist(&bgr_planes[0], 1, 0, cv::Mat(), b_hist, 1, 26 &histSize, &histRange, uniform, accumulate); 27 calcHist(&bgr_planes[1], 1, 0, cv::Mat(), g_hist, 1, 28 &histSize, &histRange, uniform, accumulate); 29 calcHist(&bgr_planes[2], 1, 0, cv::Mat(), r_hist, 1, 30 &histSize, &histRange, uniform, accumulate); 31 // 设置直方图绘图参数 32 int hist_w = 640; int hist_h = 512; 33 int bin_w = cvRound((double)hist_w / histSize); 34 cv::Mat histImage(hist_h, hist_w, 35 CV_8UC3, cv::Scalar(0, 0, 0)); 36 // 分别归一化直方图到[ 0, histImage.rows ] 37 normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, 38 -1, Mat()); 39 normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, 40 -1, Mat()); 41 normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, 42 -1, Mat()); 43 // 分别对每个通道进行绘图 44 for (int i = 1; i < histSize; i++) 45 { 46 line(histImage, Point(bin_w*(i - 1), 47 hist_h - cvRound(b_hist.at<float>(i - 1))), 48 Point(bin_w*(i), hist_h - 49 cvRound(b_hist.at<float>(i))), 50 Scalar(255, 0, 0), 2, 8, 0); 51 line(histImage, Point(bin_w*(i - 1), hist_h - 52 cvRound(g_hist.at<float>(i - 1))), 53 Point(bin_w*(i), hist_h - 54 cvRound(g_hist.at<float>(i))), 55 Scalar(0, 255, 0), 2, 8, 0); 56 line(histImage, Point(bin_w*(i - 1), hist_h - 57 cvRound(r_hist.at<float>(i - 1))), 58 Point(bin_w*(i), hist_h - 59 cvRound(r_hist.at<float>(i))), 60 Scalar(0, 0, 255), 2, 8, 0); 61 } 62 imshow("calcHist", histImage); 63 cv::waitKey(0); 64 return 0; 65 }
1 ////https://blog.csdn.net/dainesao/article/details/79184934 2 ////3.2.3B-G-R直方图方法2: 3 #include <opencv2/opencv.hpp> 4 #include <opencv2/imgproc/imgproc.hpp> 5 6 using namespace cv; 7 8 int main() 9 { 10 Mat srcImage; 11 srcImage = imread("D:\\lena.jpg"); 12 imshow("素材图", srcImage); 13 int bins = 256; 14 int hist_size[] = { bins }; 15 float range[] = { 0, 256 }; 16 const float* ranges[] = { range }; 17 MatND redHist, grayHist, blueHist; 18 19 //进行直方图的计算(红色分量部分) 20 int channels_r[] = { 0 }; 21 calcHist(&srcImage, 1, channels_r, Mat(), 22 redHist, 1, hist_size, ranges, 23 true, false); 24 25 //进行直方图的计算(绿色分量部分) 26 int channels_g[] = { 1 }; 27 calcHist(&srcImage, 1, channels_g, Mat(), // do not use mask 28 grayHist, 1, hist_size, ranges, 29 true, // the histogram is uniform 30 false); 31 32 //进行直方图的计算(蓝色分量部分) 33 int channels_b[] = { 2 }; 34 calcHist(&srcImage, 1, channels_b, Mat(), // do not use mask 35 blueHist, 1, hist_size, ranges, 36 true, // the histogram is uniform 37 false); 38 39 //-----------------------绘制出三色直方图------------------------ 40 //参数准备 41 double maxValue_red, maxValue_green, maxValue_blue; 42 minMaxLoc(redHist, 0, &maxValue_red, 0, 0); 43 minMaxLoc(grayHist, 0, &maxValue_green, 0, 0); 44 minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0); 45 int scale = 1; 46 int histHeight = 256; 47 Mat histImage = Mat::zeros(histHeight, bins * 3, CV_8UC3); 48 49 //正式开始绘制 50 for (int i = 0; i<bins; i++) 51 { 52 //参数准备 53 float binValue_red = redHist.at<float>(i); 54 float binValue_green = grayHist.at<float>(i); 55 float binValue_blue = blueHist.at<float>(i); 56 int intensity_red = cvRound(binValue_red*histHeight / maxValue_red); //要绘制的高度 57 int intensity_green = cvRound(binValue_green*histHeight / maxValue_green); //要绘制的高度 58 int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue); //要绘制的高度 59 60 //绘制红色分量的直方图 61 rectangle(histImage, Point(i*scale, histHeight - 1), 62 Point((i + 1)*scale - 1, histHeight - intensity_red), 63 Scalar(255, 0, 0)); 64 65 //绘制绿色分量的直方图 66 rectangle(histImage, Point((i + bins)*scale, histHeight - 1), 67 Point((i + bins + 1)*scale - 1, histHeight - intensity_green), 68 Scalar(0, 255, 0)); 69 70 //绘制蓝色分量的直方图 71 rectangle(histImage, Point((i + bins * 2)*scale, histHeight - 1), 72 Point((i + bins * 2 + 1)*scale - 1, histHeight - intensity_blue), 73 Scalar(0, 0, 255)); 74 75 } 76 77 //在窗口中显示出绘制好的直方图 78 imshow("图像的RGB直方图", histImage); 79 waitKey(0); 80 return 0; 81 }
3.2.4 自定义直方图
1 ////https://blog.csdn.net/gone_huilin/article/details/53222859 2 #include <opencv2/opencv.hpp> 3 int main() 4 { 5 // 图像获取及判断 6 cv::Mat srcImage = cv::imread("D:\\lena.jpg"); 7 if (!srcImage.data) 8 return 1; 9 cv::imshow("srcImage", srcImage); 10 // 灰度转换 11 cv::Mat srcGray; 12 cv::cvtColor(srcImage, srcGray, CV_BGR2GRAY); 13 // 初始化直方图计算参数 14 const int channels[1] = { 0 }; 15 const int histSize[1] = { 256 }; 16 // 设定区间[0 60],[61 120],[121 160],[161 220],[221 255] 17 float hranges[6] = { 0, 60, 120, 160, 220, 255 }; 18 const float* ranges[1] = { hranges }; 19 cv::MatND hist; 20 // 计算直方图 21 cv::calcHist(&srcGray, 1, 22 channels, cv::Mat(), 23 hist, 1, histSize, 24 ranges); 25 // 求直方图中最大值 26 double maxHist = 0; 27 cv::minMaxLoc(hist, 0, &maxHist, 0, 0); 28 // 设置直方图绘图参数 29 int hist_Size = hist.rows; 30 cv::Mat histImg(hist_Size, hist_Size, 31 CV_8U, cv::Scalar(255)); 32 // 直方图绘制 33 for (int h = 0; h < hist_Size; h++) 34 { 35 float binVal = hist.at<float>(h); 36 //归一化 根据最大值计算变换范围 37 int intensity = static_cast<int>(binVal * 38 hist_Size / maxHist); 39 // 绘图直方图信息 40 cv::line(histImg, cv::Point(h, hist_Size), 41 cv::Point(h, hist_Size - intensity), 42 cv::Scalar::all(0)); 43 } 44 cv::imshow("histImg", histImg); 45 cv::waitKey(0); 46 return 0; 47 }
3.2.5灰度直方图均衡
1 //////////////////////////3.2.5灰度直方图均衡/////////////////////////// 2 ////https://blog.csdn.net/linqianbi/article/details/78603406 3 #include<opencv2\opencv.hpp> 4 #include<cmath> 5 #include<iostream> 6 using namespace cv; 7 using namespace std; 8 Mat MyequalizeHist(Mat &srcImage) 9 { 10 int nRows = srcImage.rows; 11 int nCols = srcImage.cols; 12 13 int nSumPix[256]; 14 double nProDis[256]; 15 double nSumProDis[256]; 16 int EqualizeSumPix[256]; 17 18 for (int i = 0; i < 256; i++) 19 { 20 nSumPix[i] = 0; 21 nProDis[i] = 0.0; 22 nSumProDis[i] = 0.0; 23 EqualizeSumPix[i] = 0; 24 } 25 26 for (int i = 0; i < nRows; i++) 27 { 28 for (int j = 0; j < nCols; j++) 29 { 30 nSumPix[(int)srcImage.at<uchar>(i, j)]++; 31 } 32 } 33 34 35 for (int i = 0; i < 256; i++) 36 { 37 nProDis[i] = (double)nSumPix[i] / (nRows * nCols); 38 } 39 40 41 nSumProDis[0] = nProDis[0]; 42 43 44 for (int i = 1; i < 256; i++) 45 { 46 nSumProDis[i] = nSumProDis[i - 1] + nProDis[i]; 47 } 48 49 50 for (int i = 0; i < 256; i++) 51 { 52 EqualizeSumPix[i] = cvRound((double)nSumProDis[i] * 255); 53 } 54 55 Mat resultImage(nRows, nCols, srcImage.type()); 56 for (int i = 0; i < nRows; i++) 57 { 58 59 for (int j = 0; j < nCols; j++) 60 { 61 62 resultImage.at<uchar>(i, j) = EqualizeSumPix[(int)srcImage.at<uchar>(i, j)]; 63 } 64 } 65 return resultImage; 66 67 } 68 int main() 69 { 70 Mat srcIamge = imread("D:\\lena.jpg"); 71 if (!srcIamge.data) 72 { 73 printf("image could not load...\n"); 74 return -1; 75 } 76 Mat srcGray; 77 //转化为灰度图并且显示 78 cvtColor(srcIamge, srcGray, CV_BGR2GRAY); 79 imshow("srcGray", srcGray); 80 81 Mat resultImage = MyequalizeHist(srcGray); 82 imshow("res", resultImage); 83 84 waitKey(0); 85 return 0; 86 }
参考:
https://blog.csdn.net/linqianbi/article/details/78603406
https://blog.csdn.net/xiaowei_cqu/article/details/7606607
https://www.cnblogs.com/wangguchangqing/p/7098213.html
https://blog.csdn.net/sunmc1204953974/article/details/50606395
https://blog.csdn.net/zhulf0804/article/details/52770613/
3.2.6彩色直方图均衡化
1 ////3.2.6彩色直方图均衡化方法1:与方法2不同在于使用Mat数组 2 ////Source code:https://blog.csdn.net/dcrmg/article/details/53677739 3 ////对RGB三通道各自均衡化后,再组合输出结果 4 #include <opencv2/highgui/highgui.hpp> 5 #include <opencv2/imgproc/imgproc.hpp> 6 #include <iostream> 7 8 using namespace cv; 9 10 int main(int argc, char *argv[]) 11 { 12 Mat image = imread("D:\\西藏.jpg"); 13 if (image.empty()) 14 { 15 std::cout << "打开图片失败,请检查" << std::endl; 16 return -1; 17 } 18 imshow("原图像", image); 19 Mat imageRGB[3]; 20 split(image, imageRGB); 21 for (int i = 0; i < 3; i++) 22 { 23 equalizeHist(imageRGB[i], imageRGB[i]); 24 } 25 merge(imageRGB, 3, image); 26 imshow("直方图均衡化图像增强效果", image); 27 waitKey(); 28 return 0; 29 }
1 /////https://blog.csdn.net/kuweicai/article/details/73824485 2 #include<opencv.hpp> 3 #include<iostream> 4 5 //绘制直方图,src为输入的图像,histImage为输出的直方图,name是输出直方图的窗口名称 6 void drawHistImg(cv::Mat &src, cv::Mat &histImage, std::string name) 7 { 8 const int bins = 256; 9 int hist_size[] = { bins }; 10 float range[] = { 0, 256 }; 11 const float* ranges[] = { range }; 12 cv::MatND hist; 13 int channels[] = { 0 }; 14 15 cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, hist_size, ranges, true, false); 16 17 double maxValue; 18 cv::minMaxLoc(hist, 0, &maxValue, 0, 0); 19 int scale = 1; 20 int histHeight = 256; 21 22 for (int i = 0; i < bins; i++) 23 { 24 float binValue = hist.at<float>(i); 25 int height = cvRound(binValue*histHeight / maxValue); 26 cv::rectangle(histImage, cv::Point(i*scale, histHeight), cv::Point((i + 1)*scale, histHeight - height), cv::Scalar(255)); 27 28 cv::imshow(name, histImage); 29 } 30 } 31 32 int main(void) 33 { 34 cv::Mat src, dst; 35 36 src = cv::imread("D:\\西藏.jpg", CV_LOAD_IMAGE_GRAYSCALE); 37 if (!src.data) 38 std::cout << "ERR"; 39 cv::equalizeHist(src, dst); 40 41 cv::imshow("src", src); 42 cv::imshow("equalizeHist", dst); 43 44 cv::Mat srcHistImage = cv::Mat::zeros(256, 256, CV_8UC1); 45 cv::Mat dstHistImage = cv::Mat::zeros(256, 256, CV_8UC1); 46 drawHistImg(src, srcHistImage, "srcHistImage"); 47 drawHistImg(dst, dstHistImage, "dstHistImage"); 48 49 cvWaitKey(0); 50 return 0; 51 }
由于opencv自带的函数是对灰度图像进行直方图均衡化的,所以不可直接调用函数。需要注意的是对于彩色图像(RGB),直接对三个通道单独进行直方图均衡化,然后合成是不可取的,原因是直方图均衡化并非线性操作,这样会引起彩色失真,可取的方式是将RGB转换到HSV,HSI,YUV 或者YCbCr,然后对亮度(即前面的V, I,Y通道)进度均衡化,这样不会对彩色的色调产生影响,然后转换回RGB空间即可。这里特别推荐最后一个YCbCr,因为它就是专门为数字图像所设计的。
1 ////// RGB图像转化为YCbCr(HSI,YUV)颜色空间后,对亮度通道进行均衡化运算后再转回RGB空间 2 //////https://blog.csdn.net/kuweicai/article/details/73824485 3 #include<opencv.hpp> 4 #include<iostream> 5 6 //绘制直方图,src为输入的图像,histImage为输出的直方图,name是输出直方图的窗口名称 7 void drawHistImg(cv::Mat &src, cv::Mat &histImage, std::string name) 8 { 9 const int bins = 256; 10 int hist_size[] = { bins }; 11 float range[] = { 0, 256 }; 12 const float* ranges[] = { range }; 13 cv::MatND hist; 14 int channels[] = { 0 }; 15 16 cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, hist_size, ranges, true, false); 17 18 double maxValue; 19 cv::minMaxLoc(hist, 0, &maxValue, 0, 0); 20 int scale = 1; 21 int histHeight = 256; 22 23 for (int i = 0; i < bins; i++) 24 { 25 float binValue = hist.at<float>(i); 26 int height = cvRound(binValue*histHeight / maxValue); 27 cv::rectangle(histImage, cv::Point(i*scale, histHeight), cv::Point((i + 1)*scale, histHeight - height), cv::Scalar(255)); 28 29 cv::imshow(name, histImage); 30 } 31 } 32 33 int main(void) 34 { 35 cv::Mat src, dst; 36 cv::Mat srcHistImage = cv::Mat::zeros(256, 256, CV_8UC1); 37 cv::Mat dstHistImage = cv::Mat::zeros(256, 256, CV_8UC1); 38 39 src = cv::imread("D:\\西藏.jpg"); 40 if (!src.data) 41 std::cout << "ERR"; 42 43 cv::Mat YCC; 44 cv::cvtColor(src, YCC, cv::COLOR_RGB2YCrCb); 45 //std::vector<cv::Mat> channels; 46 cv::Mat channels[3]; 47 cv::split(YCC, channels); 48 49 drawHistImg(channels[0], srcHistImage, "srcHistImage"); 50 cv::equalizeHist(channels[0], channels[0]);//对Y通道进行均衡化 51 52 cv::merge(channels, 3, YCC); 53 cv::cvtColor(YCC, dst, cv::COLOR_YCrCb2RGB);//重新转换到RGB颜色域 54 55 cv::imshow("src", src); 56 cv::imshow("dst", dst); 57 58 drawHistImg(channels[0], dstHistImage, "dstHistImage"); 59 60 cvWaitKey(0); 61 return 0; 62 63 }
主要参考:
https://blog.csdn.net/kuweicai/article/details/73824485
https://blog.csdn.net/dcrmg/article/details/53677739
RGB各通道直方图均衡化后图像与YCbCr 亮度通道Y直方图均衡化后图像对比参考如下:
https://blog.csdn.net/frank_xu_0818/article/details/39232157 和 https://www.cnblogs.com/yoyo-sincerely/p/6159101.html
其他:
https://blog.csdn.net/frank_xu_0818/article/details/39232157
3.2.7~3.2.10 丢了!
3.2.11 直方图的反向投影
反向投影在某一位置的值是源图像在对应位置的像素值的累计。反向投影操作可实现检测输入原图像给定图像块的最匹配区域,一般可用于基于图像内容的检索或查找特定内容。
什么是反向投影直方图呢?简单的说在灰度图像的每个点(x,y),用它对应的直方图的bin的值(就是有多少像素落在bin内)来代替它。所以·如果这个bin的值比较大,那么反向投影显示的结果会比较亮,否则就比较暗。
从统计学的角度,反输出图像象素点的值是观测数组在某个分布(直方图)下的的概率。
所以加入我们已经得到了一个物体的直方图,我们可以计算它在另一幅图像中的反向投影,来判断这幅图像中是否有该物体。
1 //////https://blog.csdn.net/gone_huilin/article/details/53222966 2 #include "opencv2/imgproc/imgproc.hpp" 3 #include "opencv2/highgui/highgui.hpp" 4 #include <iostream> 5 6 using namespace cv; 7 using namespace std; 8 9 int main() 10 { 11 // 加载源图像并验证 12 cv::Mat srcImage = cv::imread("D:\\梵高星空.jpg"); 13 if (!srcImage.data) 14 return 1; 15 // 转换到 HSV 空间 16 cv::Mat hsvImage; 17 cvtColor(srcImage, hsvImage, CV_BGR2HSV); 18 // Hue 通道分离 19 cv::Mat hueImage; 20 hueImage.create(hsvImage.size(), hsvImage.depth()); 21 int ch[] = { 0, 0 }; 22 mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1); 23 // 初始化直方图计算参数 24 int bins = 25; 25 cv::MatND hist; 26 int histSize = MAX(bins, 2); 27 float hue_range[] = { 0, 100 }; 28 const float* ranges = { hue_range }; 29 // 计算直方图 30 calcHist(&hueImage, 1, 0, cv::Mat(), 31 hist, 1, &histSize, &ranges, true, false); 32 // 归一化直方图 33 normalize(hist, hist, 0, 255, cv::NORM_MINMAX, 34 -1, cv::Mat()); 35 // 计算反向投影 36 MatND backproj; 37 calcBackProject(&hueImage, 1, 0, hist, backproj, 38 &ranges, 1, true); 39 // 定义输出图像 40 int w = 320; int h = 360; 41 int bin_w = cvRound((double)w / histSize); 42 cv::Mat histImg = cv::Mat::zeros(w, h, CV_8UC3); 43 for (int i = 0; i < bins; i++) 44 { 45 // 绘制直方图 46 rectangle(histImg, cv::Point(i * bin_w, h), 47 cv::Point((i + 1)*bin_w, 48 h - cvRound(hist.at<float>(i) * h / 255.0)), 49 cv::Scalar(0, 0, 255), -1); 50 } 51 // 显示源图像与反向投影图像 52 imshow("BackProj", backproj); 53 imshow("srcImage", srcImage); 54 imshow("Histogram", histImg); 55 // 直方图均衡化 56 cv::equalizeHist(backproj, backproj); 57 imshow("backproj_equa", backproj); 58 waitKey(0); 59 return 0; 60 }
参考:
https://blog.csdn.net/gone_huilin/article/details/53222966
https://blog.csdn.net/thefutureisour/article/details/7554716
https://www.cnblogs.com/liu-jun/p/3482211.html
https://blog.csdn.net/viewcode/article/details/8209067
https://blog.csdn.net/u012372584/article/details/18308681
https://blog.csdn.net/Jake_cai/article/details/55802702