欧,又是坑爹的opencv实验,它又来了额
实验要求:
1.输入三通道RGB直方图
2.直方图均衡化后输出图片及直方图
3.计算鸡蛋的面积(像素数)
首先什么是直方图?
横坐标是灰度,纵坐标是每一个灰度对应出现的频率,现在的彩色图象对应的直方图是R,G,B方向的,灰度不仅只有灰白通道有
直方图均衡化作用:提高图像对比度,拉伸灰度值范围,它有一个算法:
代码示例:
#include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #includeusing namespace cv; using namespace std; int main(int, char** argv) { Mat src, dst; char* yuanlaide = (char*)"yuanlaide"; char* bianhuahoude = (char*)"bianhuahoude"; src = imread("C:/echou.jpg"); if (src.empty()) { return 0; }; cvtColor(src, src, COLOR_BGR2GRAY); equalizeHist(src, dst); // 直方图 imshow(yuanlaide, src); imshow(bianhuahoude, dst); waitKey(0); return 0; }
最终显示结果如下:
原图像
变化后的图象:
感觉似乎更臭了
任务2:计算图片直方图
在开始之前我们先看一个Opencv计算直方图的算法:
void cv::calcHist ( const Mat * images, int nimages, const int * channels, InputArray mask, OutputArray hist, int dims, const int * histSize, const float ** ranges, bool uniform = true, bool accumulate = false )
现在来讲解一下这个算法,在images输入图象数据,channels对应的rgb通道,https://www.cnblogs.com/phoenixdsg/p/8280362.html这里有一个详细说明这个算法的帖子大家可以看看
输出rgb代码如下:
#include "opencv2/highgui.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/imgproc.hpp" #includeusing namespace std; using namespace cv; int main( ) { Mat src, dst; src = imread("C:/echo.jpg"); if (src.empty()) { return -1; } vector bgr_planes; // 矩阵向量 split(src, bgr_planes); // 将多通道图像分为多个单通道图像 int histSize = 256; float range[] = { 0,256 }; const float* histRange = { range }; // 必须加const,否则报错 bool uniform = true; // 直方图是否分布均匀 bool accumulate = false; // 如果为true,在开始分配时直方图不会被清除 Mat b_hist, g_hist, r_hist; calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate); calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate); calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate); int hist_w = 512, hist_h = 400; // 直方图的横纵范围 int bin_w = cvRound((double)hist_w / histSize); // 每个柱状的宽度 Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0)); normalize(b_hist, b_hist, 9, histImage.rows, NORM_MINMAX, -1, Mat()); // 归一化 normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); for (int i = 1; i < histSize; i++) // 绘制直线 { line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))),Scalar(255, 0, 0), 2, 8, 0); line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))),Scalar(0, 255, 0), 2, 8, 0); line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))),Scalar(0, 0, 255), 2, 8, 0); } imshow("calcHist Demo", histImage); waitKey(0); return 0; }
运行之后输出了恶臭先辈的直方图
紧接着就是万众瞩目的计算鸡蛋面积
看看这个蛋,表面上只是一个蛋,其实它不是普通的蛋,它是一种叫做“公鸡蛋”的蛋
什么?公鸡为什么会下蛋呢?公鸡生来就有蛋蛋啊,这不是显而易见的事情吗?
废话不多说,直接开搞!
先考虑对这一张图片进行处理,进行高斯滤波
Mat dst,dstGray,thres; Mat img = imread("C:/egg.jpg"); GaussianBlur(img, dst, Size(7,7), 0); //高斯变换
紧接着考虑进行灰度变换后二值化,变成只有黑和白的两种颜色,这样可以方便处理
cvtColor(dst,dstGray, CV_BGR2GRAY); //灰度化 threshold(dstGray, thres, 80, 255, CV_THRESH_BINARY);
紧接着考虑对二值化后的图片进行平滑处理
Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3),Point(-1,-1)); morphologyEx(thres,morp,MORPH_CLOSE,kernel,Point(1,-1),2);
现在开始进行正式的计算了,这里原理是计算白色区块的总像素个数
vector>contours; vector hireachy; findContours(morp,contours,hireachy,CV_RETR_EXTERNAL,CHAIN_APPROX_SIMPLE,Point()); Mat result = Mat::zeros(img.size(),CV_8UC3); for (size_t t = 0; t < contours.size(); t++) { Rect rect = boundingRect(contours[t]); if (rect.width < img.cols / 2) { continue; } if (rect.width > img.cols - 20) { continue; } double area = contourArea(contours[t]); double len = arcLength(contours[t], true); drawContours(result, contours, static_cast<int>(t), Scalar(0, 0, 255), 1, 8, hireachy); cout << area << endl; }
好了,到这里输出了area的大小,也就是鸡蛋的面积。
谢谢各位!