BS版图形系统 - OpenCV - 第4章笔记
QQ: 282397369
4 深入研究直方图和滤波器
4.1 技术要求
4.2 生成CMake脚本文件
4.3 创建图形用户界面
- Show histogram
- Equalize histogram
- Lomography effect
- Cartoonize effect
4.4 绘制直方图
- split
vector<Mat> bgr; // 3个矩阵来处理每个输入图像通道
split(img, bgr); // 划分成3个通道
int numbins = 256; // 定义直方图的区间数[每个可能的像素值对应一个区间]
float range[] = {0, 256}; // 定义变量范围
const float * histRange = {range};
Mat b_hist, g_hist, r_hist; // 创建3个矩阵来存储每个直方图
calcHist( &bgr[0], 1, 0, Mat(), b_hist, 1, &numbins, &histRange );
calcHist( &bgr[1], 1, 0, Mat(), g_hist, 1, &numbins, &histRange );
calcHist( &bgr[2], 1, 0, Mat(), r_hist, 1, &numbins, &histRange );
Mat histImage( height, width, CV_8UC3, Scalar(20,20,20) ); // 准备绘制
normalize(b_hist, b_hist, 0, height,NORM_MINMAX ); // 标准化直方图矩阵[最大值与输出直方图图像的高度相同]
normalize(g_hist, g_hist, 0, height, NORM_MINMAX );
normalize(r_hist, r_hist, 0, height, NORM_MINMAX );
int binStep=cvRound((float)width/(float)numbins);
for( int i=1; i< numbins; i++)
{
line( histImage,
Point( binStep*(i-1), height-cvRound(b_hist.at<float>(i-1) ) ),
Point( binStep*(i), height-cvRound(b_hist.at<float>(i) ) ),
Scalar(255,0,0)
);
line( histImage,
Point( binStep*(i-1), height-cvRound(g_hist.at<float>(i-1) ) ),
Point( binStep*(i), height-cvRound(g_hist.at<float>(i) ) ),
Scalar(0,255,0)
);
line( histImage,
Point( binStep*(i-1), height-cvRound(r_hist.at<float>(i-1) ) ),
Point( binStep*(i), height-cvRound(r_hist.at<float>(i) ) ),
Scalar(0,0,255)
);
}
4.5 图像颜色均衡
为了均衡彩色图像,只需均衡亮度通道。可用HSV或YCrCb来分离亮度分量
Mat ycrcb;
cvtColor( img, ycrcb, COLOR_BGR2YCrCb); // 将BGR图像转换为YCrCb
// Split image into channels
vector<Mat> channels; // 分离YCrCb图像为不同的通道矩阵
split( ycrcb, channels );
// Equalize the Y channel only
equalizeHist( channels[0], channels[0] ); // Y通道(0)为亮度,输入 -> 输出
// Merge the result channels
merge( channels, ycrcb ); // 合并成YCrCb
// Convert color ycrcb to BGR
cvtColor( ycrcb, result, COLOR_YCrCb2BGR ); // 转换为BGR格式
4.6 Lomography效果
- Google相机、Instagram
- LUT:查找表
- 示例:仅用于红色通道、对图像应用暗晕来实现复古效果
示例中,取s=0.1。s越低越暗
const double E = std::exp(1.0);
// Create Lookup table for color curve effect
Mat lut(1, 256, CV_8UC1);
for (int i=0; i<256; i++)
{
float x= (float)i/256.0;
lut.at<uchar>(i)= cvRound( 256 * (1/(1 + pow(E, -((x-0.5)/0.1)) )) );
}
// Split the image channels and apply curve transform only to red channel
vector<Mat> bgr;
split(img, bgr);
LUT(bgr[2], lut, bgr[2]);
// merge result
merge(bgr, result);
// Create image for halo dark
Mat halo( img.rows, img.cols, CV_32FC3, Scalar(0.3,0.3,0.3) );
// Create circle
circle(halo, Point(img.cols/2, img.rows/2), img.cols/3, Scalar(1,1,1), -1);
blur(halo, halo, Size(img.cols/3, img.cols/3));
// Convert the result to float to allow multiply by 1 factor
Mat resultf;
result.convertTo(resultf, CV_32FC3);
// Multiply our result with halo
multiply(resultf, halo, resultf);
// convert to 8 bits
resultf.convertTo(result, CV_8UC3);
// show result
imshow("Lomograpy", result);
// Release mat memory
halo.release();
resultf.release();
lut.release();
bgr[0].release();
bgr[1].release();
bgr[2].release();
4.7 卡通效果
- 边缘检测和颜色过滤
Mat imgMedian;
medianBlur(img, imgMedian, 7); // 模糊,以便检测强边缘
// Detect edges with canny
Mat imgCanny;
Canny(imgMedian, imgCanny, 50, 150); // 边缘检测
// Dilate the edges
Mat kernel= getStructuringElement(MORPH_RECT, Size(2,2));
dilate(imgCanny, imgCanny, kernel); // 扩张一下,以连接断开的边缘
// Scale edges values to 1 and invert values
imgCanny= imgCanny/255; // 准备相乘,归一化后反转
imgCanny= 1-imgCanny;
// Use float values to allow multiply between 0 and 1
Mat imgCannyf;
imgCanny.convertTo(imgCannyf, CV_32FC3); // 将其转化为浮点矩阵
// Blur the edgest to do smooth effect
blur(imgCannyf, imgCannyf, Size(5,5)); // 模糊边缘,以给出平滑的结果线
/** COLOR **/
// Apply bilateral filter to homogenizes color
Mat imgBF;
bilateralFilter(img, imgBF, 9, 150.0, 150.0); // 采用双边滤波[保持边缘的同时降低图像的噪声],以获得卡通外观
// truncate colors
Mat result= imgBF/25; // 更强大的卡通效果,阶梯量化
result= result*25;
/** MERGES COLOR + EDGES **/
// Create a 3 channles for edges
Mat imgCanny3c;
Mat cannyChannels[]={ imgCannyf, imgCannyf, imgCannyf};
merge(cannyChannels, 3, imgCanny3c);
// Convert color result to float
Mat resultf;
result.convertTo(resultf, CV_32FC3);
// Multiply color and edges matrices
multiply(resultf, imgCanny3c, resultf);
// convert to 8 bits color
resultf.convertTo(result, CV_8UC3);
- 模糊:高斯、中值…
- 边缘:Canny过滤器检测强边缘