OPENCV图像变换-1
圖像變換是指將一幅圖像變換為圖像數(shù)據(jù)的另一種表現(xiàn)形式,例如將圖像進(jìn)行傅立葉變換,或者對(duì)圖像進(jìn)行X,Y方向的求導(dǎo)等,經(jīng)過這些變換,可以將圖像數(shù)據(jù)處理中的某些問題換一個(gè)別的角度想辦法,所以圖像變換是圖像處理的時(shí)候比較常用的一種方法.
???????? 一.sobel算子
???????? sobel算子是一個(gè)用于邊緣檢測(cè)的離散微分算子,其結(jié)合了高斯平滑和微分求導(dǎo),用于計(jì)算圖像灰度函數(shù)的近似梯度,在圖像的任何一點(diǎn)使用該函數(shù),都將產(chǎn)生對(duì)應(yīng)的梯度矢量或者是發(fā)矢量,簡單地說,sobel算子適用于計(jì)算出圖像像素點(diǎn)之間變化幅度的算子,而邊緣的變化幅度是最劇烈的,所以sobel算子能用來做邊緣檢測(cè).
???????? sobel算子分方向,在x,y方向指定階數(shù).
???????? API:void sobel(輸入源,輸出,int 輸出圖像深度,int X方向差分階數(shù),int y方向差分階數(shù),int sobel鄰域核大小,double 可選的縮放因子,double 可選的delata值,double 邊界模式)
???????? 注:源圖像和目標(biāo)圖像尺寸類型一致,,輸出圖像的深度根據(jù)源圖像的深度決定,默認(rèn)為-1,輸出圖像必須比源圖像的數(shù)據(jù)更寬,sobel核大小默認(rèn)為3,只能為1,3,5,7其中之一,縮放因子默認(rèn)為-1,不縮放,delate值默認(rèn)為.0
???????? 實(shí)際功能代碼如下
Mat srcImage,sobelxImage,sobelxAbsImage,sobelyImage,sobelyAbsImage,dstImage;const int g_sobelCoreMax = 2; int g_sobelCoreValue;const int g_deltaxMax = 9; int g_deltaxValue;const int g_deltayMax = 9; int g_deltayValue;void onTrackBarSobelCore(int pos,void* userData); void onTrackBarSobelDeltax(int pos,void* userData); void onTrackBarSobelDeltay(int pos,void* userData);int main(int argc,char* argv[]) {srcImage = imread("F:\\opencv\\OpenCVImage\\sobel.jpg");namedWindow("src image");namedWindow("sobelx image");namedWindow("sobely image");namedWindow("sobelxy image");g_sobelCoreValue = 0;g_deltaxValue = 0;g_deltayValue = 0;createTrackbar("core size", "src image", &g_sobelCoreValue, g_sobelCoreMax,onTrackBarSobelCore,0);createTrackbar("deltax value", "src image", &g_deltaxValue, g_deltaxMax,onTrackBarSobelDeltax,0);createTrackbar("deltay value", "src image", &g_deltayValue, g_deltayMax,onTrackBarSobelDeltay,0);onTrackBarSobelCore(g_sobelCoreValue, 0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("sobelx image", srcImage.cols, 0);moveWindow("sobely image", 0, srcImage.rows);moveWindow("sobelxy image", srcImage.cols, srcImage.rows);waitKey(0);return 0; }void onTrackBarSobelCore(int pos,void* userData) {int coreSize = g_sobelCoreValue*2+3;int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Sobel(srcImage, sobelxImage, CV_16S, deltax, 0,coreSize);Sobel(srcImage, sobelyImage, CV_16S, 0, deltay,coreSize);convertScaleAbs(sobelxImage, sobelxAbsImage);convertScaleAbs(sobelyImage, sobelyAbsImage);addWeighted(sobelxAbsImage, 0.5, sobelyAbsImage, 0.5, 0.0, dstImage);imshow("sobelx image", sobelxAbsImage);imshow("sobely image", sobelyAbsImage);imshow("sobelxy image", dstImage); }void onTrackBarSobelDeltax(int pos,void* userData) {int coreSize = g_sobelCoreValue*2+3;int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Sobel(srcImage, sobelxImage, CV_16S, deltax, 0,coreSize);Sobel(srcImage, sobelyImage, CV_16S, 0, deltay,coreSize);convertScaleAbs(sobelxImage, sobelxAbsImage);convertScaleAbs(sobelyImage, sobelyAbsImage);addWeighted(sobelxAbsImage, 0.5, sobelyAbsImage, 0.5, 0.0, dstImage);imshow("sobelx image", sobelxAbsImage);imshow("sobely image", sobelyAbsImage);imshow("sobelxy image", dstImage); }void onTrackBarSobelDeltay(int pos,void* userData) {int coreSize = g_sobelCoreValue*2+3;int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Sobel(srcImage, sobelxImage, CV_16S, deltax, 0,coreSize);Sobel(srcImage, sobelyImage, CV_16S, 0, deltay,coreSize);convertScaleAbs(sobelxImage, sobelxAbsImage);convertScaleAbs(sobelyImage, sobelyAbsImage);addWeighted(sobelxAbsImage, 0.5, sobelyAbsImage, 0.5, 0.0, dstImage);imshow("sobelx image", sobelxAbsImage);imshow("sobely image", sobelyAbsImage);imshow("sobelxy image", dstImage); }
當(dāng)Ksize為1的時(shí)候,僅使用1*3內(nèi)核或者3*1內(nèi)核,而且沒有平滑操作.
二.scharr算子
???????? 當(dāng)sobel算子核大小為3的時(shí)候,因?yàn)橛?jì)算使用的是導(dǎo)數(shù)的近似值,為了解決ksize為3的時(shí)候的誤差問題,opencv引入了函數(shù)scharr,scharr和sobel一樣快,但是結(jié)果更加精確
???????? 另外,對(duì)于sobel,因?yàn)槟繕?biāo)圖像的深度一般比源圖像的深度更深,所以為了正常的顯示目標(biāo)圖像,我們可以使用convertScalarAbs()函數(shù),將深度縮放為八位數(shù)字圖像,便于顯示和保存.
???????? API:void scharr(源圖像,目標(biāo)圖像, int 輸出圖像深度,int X方向差分階數(shù),int y方向差分階數(shù) ,double 可選的縮放因子,double 可選的delata值,double 邊界模式)
???????? 注:和sobel相比少了一個(gè)鄰域核大小,因?yàn)槟J(rèn)為3
使用例程代碼如下
Mat srcImage,scharrxImage,scharrxAbsImage,scharryImage,scharryAbsImage,dstImage; const int g_deltaxMax = 0; int g_deltaxValue; const int g_deltayMax = 0; int g_deltayValue; void onTrackBarScharrDeltax(int pos,void* userData); void onTrackBarScharrDeltay(int pos,void* userData);int main(int argc,char* argv[]) {srcImage = imread("F:\\opencv\\OpenCVImage\\scharr.jpg");namedWindow("src image");namedWindow("scharrx image");namedWindow("scharry image");namedWindow("scharrxy image");g_deltaxValue = 0;g_deltayValue = 0;createTrackbar("deltax value", "src image", &g_deltaxValue, g_deltaxMax,onTrackBarScharrDeltax,0);createTrackbar("deltay value", "src image", &g_deltayValue, g_deltayMax,onTrackBarScharrDeltay,0);onTrackBarScharrDeltax(g_deltaxValue,0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("scharrx image", srcImage.cols, 0);moveWindow("scharry image", 0, srcImage.rows);moveWindow("scharrxy image", srcImage.cols, srcImage.rows);waitKey(0);return 0; }void onTrackBarScharrDeltax(int pos,void* userData) {int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Scharr(srcImage, scharrxImage, CV_16S, deltax, 0);Scharr(srcImage, scharryImage, CV_16S, 0, deltay);convertScaleAbs(scharrxImage, scharrxAbsImage);convertScaleAbs(scharryImage, scharryAbsImage);addWeighted(scharrxAbsImage, 0.5, scharryAbsImage, 0.5, 0.0, dstImage);imshow("scharrx image", scharrxAbsImage);imshow("scharry image", scharryAbsImage);imshow("scharrxy image", dstImage); } void onTrackBarScharrDeltay(int pos,void* userData) {int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Scharr(srcImage, scharrxImage, CV_16S, deltax, 0);Scharr(srcImage, scharryImage, CV_16S, 0, deltay);convertScaleAbs(scharrxImage, scharrxAbsImage);convertScaleAbs(scharryImage, scharryAbsImage);addWeighted(scharrxAbsImage, 0.5, scharryAbsImage, 0.5, 0.0, dstImage);imshow("scharrx image", scharrxAbsImage);imshow("scharry image", scharryAbsImage);imshow("scharrxy image", dstImage); }三.laplacian算子 (拉普拉斯算子)
???????? 有時(shí)候我們需要在X和y方向上同時(shí)差分,然后看整體的結(jié)果,這就需要用到laplacian算子,該算子是N維歐幾里德空間中的二階微分算子.
???????? 讓一幅圖的源圖像減去其拉普拉斯算子的結(jié)果,圖像的對(duì)比度將變得更強(qiáng)
???????? API:void laplacian(源圖像,目標(biāo)圖像,目標(biāo)深度,int 鄰域孔徑尺寸,int 可選的縮放比例因子,int deleta可選值,int 邊界模式);
???????? 注:圖像深度和sobel一致,cv_8u對(duì)應(yīng)cv_16s,ksize默認(rèn)為1,且必須是正奇數(shù).
???????? 實(shí)際上,laplacian是圖像在x方向上的sobel算子和y方向上的sobel算子的和,使用這種算子之前,最好先進(jìn)行圖像的濾波操作,防止引入微笑誤差.
使用代碼
// lapacian拉普拉斯算子 Mat srcImage,srcImageGassianBlur,srcImageGray,laplacianImage,laplacianAbs; const int g_coreSizeMax = 5; int g_coreSizeValue; void onTrackBarCoreSize(int pos,void* userData);int main(int argc,char* argv[]) {srcImage = imread("F:\\opencv\\OpenCVImage\\laplacian.jpg");GaussianBlur(srcImage, srcImageGassianBlur, Size(3,3), 0);cvtColor(srcImageGassianBlur, srcImageGray, CV_RGB2GRAY);namedWindow("src image");namedWindow("dst image");g_coreSizeValue = 0;createTrackbar("core size", "dst image", &g_coreSizeValue, g_coreSizeMax,onTrackBarCoreSize,0);onTrackBarCoreSize(g_coreSizeValue, 0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("dst image", srcImage.cols, 0);waitKey(0);return 0; }void onTrackBarCoreSize(int pos,void* userData) {int coreSize = g_coreSizeValue*2 + 1;Laplacian(srcImageGray, laplacianImage, CV_16S,coreSize);convertScaleAbs(laplacianImage, laplacianAbs);imshow("dst image", laplacianAbs); }四.canny邊緣檢測(cè)
???????? 邊緣檢測(cè)在工程上,有極大的應(yīng)用,依靠邊緣,確定物體的形狀,檢測(cè)產(chǎn)品的良好程度,canny算法,是opencv中提供的很不錯(cuò)的邊緣檢測(cè)算法,其檢測(cè)邊緣的步驟如下.
???????? 首先是濾波,使用高斯平滑濾波卷積降噪.然后是計(jì)算梯度幅值與方向,類似于sobel ,laplacian,第三是非極大值一致,排除掉不是邊緣的像素,最后是之后閾值化,使用兩個(gè)閾值,并且綁定的時(shí)候考慮顏色之間的關(guān)聯(lián)關(guān)系(高低閾值的比例在1:2或者1:3之間).
???????? API:void canny(輸入圖像,輸出圖像,double 低與閾值,double 高閾值,int sobel算子孔徑,bool 計(jì)算梯度幅值標(biāo)志);
???????? 注:sobel算子孔徑默認(rèn)為3,計(jì)算梯度幅值的標(biāo)記默認(rèn)為false,低閾值用于控制圖像邊緣的連接,而高閾值用于控制邊緣的初始點(diǎn)位置.
???????? 另外,使用canny檢測(cè)算法之前,最好先對(duì)圖像經(jīng)過一次降噪處理.
使用例程如下
//低ì¨a閾D值|ì和¨a高?閾D值|ì默?認(rèn)¨?1:3 //sobel算?子á¨?孔?á徑?只?能¨1取¨?值|ì 3 5 7 //平?滑?濾?波?§算?子á¨?孔?á徑? 3,5,7,9 Mat srcImage,grayImage,grayBlurImage,cannyImage,dstImage;const int g_blurSizeMax = 3;//平?滑?濾?波?§孔?á徑? int g_blurValue; const int g_sobelSizeMax = 2;//sobel孔?á徑? int g_sobelValue; const int g_lowThresholdMax = 80;//邊à?緣|ì檢¨?測(cè)a低ì¨a閾D值|ì int g_lowThresholdValue; int g_upThresholdValue;void onTrackBarBlurSize(int pos,void* userData); void onTrackBarSobelSize(int pos,void* userData); void onTrackBarLowThresholdSize(int pos,void* userData);int main(int argc,char* argv[]) {srcImage = imread("F:\\opencv\\OpenCVImage\\canny2.jpg");if(srcImage.channels() != 1){cvtColor(srcImage, grayImage, CV_BGR2GRAY);}else{grayImage = srcImage.clone();}namedWindow("src image");namedWindow("dst image");g_blurValue = 1;g_sobelValue = 1;g_lowThresholdValue = 3;g_upThresholdValue = 9;createTrackbar("blur size", "dst image", &g_blurValue, g_blurSizeMax,onTrackBarBlurSize,0);createTrackbar("sobel size", "dst image", &g_sobelValue, g_sobelSizeMax,onTrackBarSobelSize,0);createTrackbar("low threshold", "dst image", &g_lowThresholdValue, g_lowThresholdMax,onTrackBarLowThresholdSize,0);onTrackBarBlurSize(g_blurValue, 0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("dst image", srcImage.cols, 0);waitKey(0);return 0; }void onTrackBarBlurSize(int pos,void* userData) {int blurValue = g_blurValue*2 +3;int sobelValue = g_sobelValue*2 +3;if (g_lowThresholdValue == 0) {g_lowThresholdValue = 1;}int lowThresholdValue = g_lowThresholdValue;int upThresholdValue = lowThresholdValue*3;//平?滑?濾?波?§ blur(srcImage, grayBlurImage, Size(blurValue,blurValue));//計(jì)?算?canny Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);dstImage = Scalar::all(0);srcImage.copyTo(dstImage, cannyImage);imshow("dst image", dstImage); } void onTrackBarSobelSize(int pos,void* userData) {int blurValue = g_blurValue*2 +3;int sobelValue = g_sobelValue*2 +3;if (g_lowThresholdValue == 0) {g_lowThresholdValue = 1;}int lowThresholdValue = g_lowThresholdValue;int upThresholdValue = lowThresholdValue*3;//平?滑?濾?波?§ blur(srcImage, grayBlurImage, Size(blurValue,blurValue));//計(jì)?算?canny Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);//用canny為掩碼?,將src拷貝到dstimage中D,應(yīng)為檢測(cè)到的線條才會(huì)得到拷貝,所以,目標(biāo)圖上檢測(cè)到的線條就會(huì)變成彩色條紋?dstImage = Scalar::all(0);srcImage.copyTo(dstImage, cannyImage);imshow("dst image", dstImage); }void onTrackBarLowThresholdSize(int pos,void* userData) {int blurValue = g_blurValue*2 +3;int sobelValue = g_sobelValue*2 +3;if (g_lowThresholdValue == 0) {g_lowThresholdValue = 1;}int lowThresholdValue = g_lowThresholdValue;int upThresholdValue = lowThresholdValue*3;//平?滑?濾?波?§ blur(srcImage, grayBlurImage, Size(blurValue,blurValue));//計(jì)?算?canny Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);dstImage = Scalar::all(0);srcImage.copyTo(dstImage, cannyImage);imshow("dst image", dstImage); }?
轉(zhuǎn)載于:https://www.cnblogs.com/dengxiaojun/p/5252234.html
總結(jié)
以上是生活随笔為你收集整理的OPENCV图像变换-1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面向对象之迪米特法则
- 下一篇: 硬盘如何分区及分区注意事项