1. 程式人生 > >OpenCV例項精解-直方圖與濾波器

OpenCV例項精解-直方圖與濾波器

原圖如下:


構造灰度直方圖:

/*構造灰度直方圖*/
void showHistoFunc()
{
	//分割通道
	vector<Mat> bgr;
	split(img, bgr);

	//建立有256個子區間的直方圖
	int numbins = 256;

	//設定範圍(B,G,R),最後一個值不包含
	float range[] = { 0, 256 };
	const float *histRange = { range };

	//計算每個直方圖
	Mat b_hist, g_hist, r_hist;
	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);

	//繪製直方圖
	int width = 512;
	int height = 300;
	Mat histImage(height, width, CV_8UC3, Scalar(20,20,20));	//以灰色為基底建立影象

	//從0到影象的高度歸一化直方圖
	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));
	}
	imshow("Histogram", histImage);
}

效果:


影象色彩均衡化(增強了對比度):

/*影象色彩均衡化:只需要均衡亮度通道(即Y通道)*/
void equalizeFunc()
{
	Mat result;
	//BGR影象轉化為YCbCr
	Mat ycrcb;
	cvtColor(img, ycrcb, COLOR_BGR2YCrCb);

	//影象通道分離
	vector<Mat> channels;
	split(ycrcb, channels);

	//只均衡y通道
	equalizeHist(channels[0], channels[0]);

	//合併結果通道
	merge(channels, ycrcb);

	//將YCrCB轉為BGR格式
	cvtColor(ycrcb, result, COLOR_YCrCb2BGR);

	imshow("Equalized", result);
}

效果:


實現Lomo效果

/*Lomo效果*/
void lomoFunc()
{
	Mat result;

	const double exponential_e = std::exp(1.0);
	//建立一個包含256個元素的對映表
	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(exponential_e, -((x - 0.5) / 0.1)))));
	}

	//拆分影象通道,並只給紅色通道應用值變換
	vector<Mat> bgr;
	split(img, bgr);
	LUT(bgr[2], lut, bgr[2]);
	//合併結果
	merge(bgr, result);

	//建立暈暗的影象
	Mat halo(img.rows, img.cols, CV_32FC3, Scalar(0.3, 0.3, 0.3));
	//建立圓
	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));

	//將結果轉化為浮點型
	Mat resultf;
	result.convertTo(resultf, CV_32FC3);

	//將結果和halo相乘
	multiply(resultf, halo, resultf);

	//轉化為8點陣圖像
	resultf.convertTo(result, CV_8UC3);

	imshow("Lomograpy", result);
}

效果:


實現卡通效果:

/* 卡通效果 */
void cartoonFunc()
{
	//------edges---------//
	//用中值濾波去除噪聲
	Mat imgMedian;
	medianBlur(img, imgMedian, 7);

	//邊緣檢測
	Mat imgCanny;
	Canny(imgMedian, imgCanny, 50, 150);

	//邊緣膨脹
	Mat kernel = getStructuringElement(MORPH_RECT, Size(2, 2));
	dilate(imgCanny, imgCanny, kernel);

	//邊緣值縮放到1, 並將值翻轉
	imgCanny = imgCanny / 255;
	imgCanny = 1 - imgCanny;

	//使用浮點值(允許在0和1之間相乘)
	Mat imgCannyf;
	imgCanny.convertTo(imgCannyf, CV_32FC3);

	//模糊邊緣(實現平滑效果)
	blur(imgCannyf, imgCannyf, Size(5, 5));

	//------color---------//
	//色彩均勻化(使用雙邊濾波器)
	Mat imgBF;
	bilateralFilter(img, imgBF, 9, 150.0, 150.0);

	//截斷顏色
	Mat result = imgBF / 25;
	result = result * 25;

	//------Merge color+edges---------//
	//為邊緣建立3個通道
	Mat imgCanny3c;
	Mat cannyChannels[] = { imgCannyf, imgCannyf, imgCannyf };
	merge(cannyChannels, 3, imgCanny3c);

	//將結果轉化為浮點型
	Mat resultf;
	result.convertTo(resultf, CV_32FC3);

	//顏色和邊緣矩陣相乘
	multiply(resultf, imgCanny3c, resultf);

	//轉化位8點陣圖像
	resultf.convertTo(result, CV_8UC3);

	imshow("cartoon", result);
}

效果: