一.經典霍夫變換算法
霍夫變換是圖像處理中的一種特徵提取技術,該方法經過在一個參數空間中經過計算累計結果的局部最大值來獲得一個符合該特定形狀的集合,做爲結果.數組
運用兩個座標空間之間的變換,將一個空間中具備相同形狀的曲線或者是直線映射到另外一個座標空間中的一個點造成峯值,從而將統計任意性狀化爲統計峯值問題.函數
opencv中,霍夫線變換市一中尋找直線的方法,在使用霍夫線變換以前,要先對圖像進行邊緣檢測的處理,霍夫變換的直接輸入爲閾值化以後的二值圖像spa
opencv至此三種不一樣的霍夫線變換,標準霍夫變換(SHT),多尺度霍夫變換(MSHT),累計機率霍夫變換(PPHT).code
PPHT是標準霍夫變換的一種改進方式,並不像標準霍夫變換同樣將累加平面的全部的點累加,而只是累加其中的一小部分,該想法是若是峯值可以足夠高,那麼只須要一小部分時間來尋找它就夠了.blog
霍夫變化的基本原理是:任意一條笛卡爾座標下的直線,均可以化爲極座標形式,直線上的某一點其通過的全部直線的參數構成一條曲線,若是圖片中有足夠多的點,這些點的曲線會有一個共同的焦點,那麼這個交點處的值就是這一條直線,只要設置足夠多的閾值,就能夠找出這一條直線.圖片
API:void houghLins(源圖像,輸出尋找到的直線,double 像素爲單位的距離精度,double 弧度爲單位的角度精度,int 累加平面的閾值,double 多尺度變換的除數距離,double 多尺度時的單位角度的除數距離);ci
注:源爲單通道,二值化圖像,目標爲輸出矢量,並不是mat,而是以極座標參數對定義,一個vector裏面包含若干參數對,距離精度爲直線搜索時,距離尺寸的增加單位,角度精度爲直線搜索時,每次增加的角度精度,閾值參數是當某一條直線被查找出來的時候,他在累加器中必須達到的累加器閾值,多尺度的角度精度和距離精度除數若是都爲0,那麼這是經典的霍夫變換.rem
經典霍夫變換的使用代碼get
Mat srcImage,srcImageGray,cannyImage; vector<Vec2f>lines; //三個變量,距離精度rho 角度精度 theta 閾值參數 threshold const int g_rhoMax = 10; int g_rhoValue; const int g_thetaMax = 200; int g_thetaValue; const int g_thresholdMax = 250; int g_thresholdValue; void onTrackBarrho(int pos,void* userData); void onTrackBartheta(int pos,void* userData); void onTrackBarThreshold(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\HoughLine.jpg"); if(srcImage.channels() == 1) { srcImageGray = srcImage.clone(); } else { cvtColor(srcImage, srcImageGray, CV_RGB2GRAY); } namedWindow("src image"); namedWindow("line image"); g_rhoValue = 0; g_thetaValue = 100; g_thresholdValue = 150; createTrackbar("rho value", "line image", &g_rhoValue, g_rhoMax,onTrackBarrho,0); createTrackbar("theta value", "line image", &g_thetaValue, g_thetaMax,onTrackBartheta ,0); createTrackbar("threshold value", "line image", &g_thresholdValue, g_thresholdMax,onTrackBarThreshold,0); onTrackBarThreshold(g_thresholdValue,0); imshow("src image", srcImageGray); moveWindow("src image", 0, 0); moveWindow("line image", srcImageGray.cols*2, 0); waitKey(0); return 0; } void onTrackBarrho(int pos,void* userData) { int rhoValue = g_rhoValue+1; int thetaValue = g_thetaValue+1; int threshold = g_thresholdValue+1; double theta = CV_PI/(double)thetaValue; Canny(srcImageGray, cannyImage, 50, 200,3); HoughLines(cannyImage, lines, rhoValue, theta, threshold,0,0); imshow("canny image", cannyImage); moveWindow("canny image", srcImageGray.cols, 0); Mat tempImage(srcImageGray.rows,srcImageGray.cols,CV_8UC3,Scalar(255,0,0)); for(size_t i = 0; i < lines.size(); i++) { float rhoResult = lines[i][0]; float thetaResult = lines[i][1]; Point pt1,pt2; double a = cos(thetaResult); double b = sin(thetaResult); double x0 = a*rhoResult; double y0 = b*rhoResult; pt1.x = cvRound(x0 + 1000*(-b)); pt1.y = cvRound(y0 + 1000*(a)); pt2.x = cvRound(x0 - 1000*(-b)); pt2.y = cvRound(y0 - 1000*(a)); line(tempImage, pt1, pt2, Scalar(0,0,255),1); } imshow("line image", tempImage); } void onTrackBartheta(int pos,void* userData) { int rhoValue = g_rhoValue+1; int thetaValue = g_thetaValue+1; int threshold = g_thresholdValue+1; double theta = CV_PI/(double)thetaValue; Canny(srcImageGray, cannyImage, 50, 200,3); HoughLines(cannyImage, lines, rhoValue, theta, threshold,0,0); imshow("canny image", cannyImage); moveWindow("canny image", srcImageGray.cols, 0); Mat tempImage(srcImageGray.rows,srcImageGray.cols,CV_8UC3,Scalar(255,0,0)); for(size_t i = 0; i < lines.size(); i++) { float rhoResult = lines[i][0]; float thetaResult = lines[i][1]; Point pt1,pt2; double a = cos(thetaResult); double b = sin(thetaResult); double x0 = a*rhoResult; double y0 = b*rhoResult; pt1.x = cvRound(x0 + 1000*(-b)); pt1.y = cvRound(y0 + 1000*(a)); pt2.x = cvRound(x0 - 1000*(-b)); pt2.y = cvRound(y0 - 1000*(a)); line(tempImage, pt1, pt2, Scalar(0,0,255),1); } imshow("line image", tempImage); } void onTrackBarThreshold(int pos,void* userData) { int rhoValue = g_rhoValue+1; int thetaValue = g_thetaValue+1; int threshold = g_thresholdValue+1; double theta = CV_PI/(double)thetaValue; Canny(srcImageGray, cannyImage, 50, 200,3); HoughLines(cannyImage, lines, rhoValue, theta, threshold,0,0); imshow("canny image", cannyImage); moveWindow("canny image", srcImageGray.cols, 0); Mat tempImage(srcImageGray.rows,srcImageGray.cols,CV_8UC3,Scalar(255,0,0)); for(size_t i = 0; i < lines.size(); i++) { float rhoResult = lines[i][0]; float thetaResult = lines[i][1]; Point pt1,pt2; double a = cos(thetaResult); double b = sin(thetaResult); double x0 = a*rhoResult; double y0 = b*rhoResult; pt1.x = cvRound(x0 + 1000*(-b)); pt1.y = cvRound(y0 + 1000*(a)); pt2.x = cvRound(x0 - 1000*(-b)); pt2.y = cvRound(y0 - 1000*(a)); line(tempImage, pt1, pt2, Scalar(0,0,255),1); } imshow("line image", tempImage); }
二.累計機率霍夫變換
累計機率霍夫變換是使用的比較多的霍夫變換,由於和標準霍夫變換比起來,累計機率霍夫變換計算快一些,而且結果也足夠精確.
API:void houghLineP(源圖像,結果向量,double 進步距離,double 進角弧度,int 累計閾值,int 最小線段長度,int 同一行點與點之間的最小鏈接距離);
注:最小線段長度,默認爲0,比這個參數短的線將不輸出在結果中,鏈接最大距離,默認值爲0,低於這個距離的將不構成同一根線,輸出的點爲四個元素的矢量,分別是(x1,y1,x2,y2);用vetc(vec4i)lines來表示,起點和終點座標.
使用代碼
Mat srcImage,srcGrayImage,cannyImage; vector<Vec4i>lines; //lowThreshold 默?認¨?upThreshold爲alowthtreshold的Ì?三¨y倍À? const int g_lowThresholdMax = 84; int g_lowThresholdValue; void onTrackBarCannyLowThreshold(int pos,void* userData); #define CALC_UPTHRESHOLD_VALUE(value) value*3; //canny sobel 孔¡Á徑? const int g_cannySobelSizeMax = 3; int g_cannySobelSizeValue; void onTrackBarCannySobelSize(int pos,void* userData); //hough 步?進?精?度¨¨ const int g_houghlineRhoMax = 9; int g_houghlineRhoValue; void onTrackBarHoughlineRhoValue(int pos,void* userData); //houghlinep 角?度¨¨精?度¨¨ const int g_houghlineThetaMax = 179; int g_houghlineThetaValue; void onTrackBarHoughlineThetaValue(int pos,void* userData); //累¤?計?閾D值¦Ì const int g_houghlineThresholdMax = 299; int g_houghlineThresholdValue; void onTrackBarHoughlineThresholdValue(int pos,void* userData); //最Á?小?線?段?長¡è度¨¨ const int g_houghlineMindistMax = 39; int g_houghlineMindistValue; void onTrackBarHoughlineMindistValue(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\HoughLineP.jpg"); if(srcImage.channels() == 1) { srcGrayImage = srcImage.clone(); } else { cvtColor(srcImage, srcGrayImage, CV_RGB2GRAY); } namedWindow("src image"); namedWindow("canny image"); namedWindow("dst image"); g_lowThresholdValue = 84; g_cannySobelSizeValue = 0; createTrackbar("low threshold", "canny image", &g_lowThresholdValue, g_lowThresholdMax,onTrackBarCannyLowThreshold,0); createTrackbar("sobel size", "canny image", &g_cannySobelSizeValue, g_cannySobelSizeMax,onTrackBarCannySobelSize,0); onTrackBarCannySobelSize(g_cannySobelSizeValue, 0); g_houghlineRhoValue = 1; g_houghlineThetaValue = 179; g_houghlineMindistValue = 19; g_houghlineThresholdValue = 10; createTrackbar("rho value", "dst image", &g_houghlineRhoValue, g_houghlineRhoMax,onTrackBarHoughlineRhoValue,0); createTrackbar("theta value", "dst image", &g_houghlineThetaValue,g_houghlineThetaMax,onTrackBarHoughlineThetaValue,0); createTrackbar("threshold value", "dst image", &g_houghlineThresholdValue, g_houghlineThresholdMax,onTrackBarHoughlineThresholdValue,0); createTrackbar("min dist", "dst image", &g_houghlineMindistValue, g_houghlineMindistMax,onTrackBarHoughlineMindistValue,0); onTrackBarHoughlineRhoValue(g_houghlineRhoValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("canny image", srcGrayImage.cols, 0); moveWindow("dst image", srcImage.cols*2, 0); waitKey(0); return 0; } void onTrackBarCannyLowThreshold(int pos,void* userData) { int sobelSize = g_cannySobelSizeValue*2+3; int lowThreshold = g_lowThresholdValue+1; int upThreshold = CALC_UPTHRESHOLD_VALUE(lowThreshold); Canny(srcGrayImage, cannyImage, lowThreshold, upThreshold,sobelSize); imshow("canny image", cannyImage); } void onTrackBarCannySobelSize(int pos,void* userData) { int sobelSize = g_cannySobelSizeValue*2+3; int lowThreshold = g_lowThresholdValue+1; int upThreshold = CALC_UPTHRESHOLD_VALUE(lowThreshold); Canny(srcGrayImage, cannyImage, lowThreshold, upThreshold,sobelSize); imshow("canny image", cannyImage); } void onTrackBarHoughlineRhoValue(int pos,void* userData) { double rhoValue = g_houghlineRhoValue+1; double thetaValue = g_houghlineThetaValue+1; int thresholdValue = g_houghlineThresholdValue+1; int minDist = g_houghlineMindistValue+1; HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist); Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); for (size_t i = 0; i < lines.size(); i++) { line(dstImage, Point(lines[i][0],lines[i][1]), Point(lines[i][2],lines[i][3]),Scalar(0,0,255),LINE_4); } imshow("dst image", dstImage); } void onTrackBarHoughlineThetaValue(int pos,void* userData) { double rhoValue = g_houghlineRhoValue+1; double thetaValue = g_houghlineThetaValue+1; int thresholdValue = g_houghlineThresholdValue+1; int minDist = g_houghlineMindistValue+1; HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist); Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); for (size_t i = 0; i < lines.size(); i++) { line(dstImage, Point(lines[i][0],lines[i][1]), Point(lines[i][2],lines[i][3]),Scalar(0,0,255),LINE_4); } imshow("dst image", dstImage); } void onTrackBarHoughlineThresholdValue(int pos,void* userData) { double rhoValue = g_houghlineRhoValue+1; double thetaValue = g_houghlineThetaValue+1; int thresholdValue = g_houghlineThresholdValue+1; int minDist = g_houghlineMindistValue+1; HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist); Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); for (size_t i = 0; i < lines.size(); i++) { line(dstImage, Point(lines[i][0],lines[i][1]), Point(lines[i][2],lines[i][3]),Scalar(0,0,255),LINE_4); } imshow("dst image", dstImage); } void onTrackBarHoughlineMindistValue(int pos,void* userData) { double rhoValue = g_houghlineRhoValue+1; double thetaValue = g_houghlineThetaValue+1; int thresholdValue = g_houghlineThresholdValue+1; int minDist = g_houghlineMindistValue+1; HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist); Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); for (size_t i = 0; i < lines.size(); i++) { line(dstImage, Point(lines[i][0],lines[i][1]), Point(lines[i][2],lines[i][3]),Scalar(0,0,255),LINE_4); } imshow("dst image", dstImage); }
三.霍夫圓變換
霍夫圓變換與霍夫線變換的原理基本一致,任意一個圓上任意一個點也能夠表示爲以圓心,半徑爲表明的一個三維空間中的曲線,多個曲線的交點,表明一個肯定的圓.
在OPENCV中,使用霍夫梯度法解決圓變換問題,具體過程是,首先對圖像進行邊緣檢測,而後計算結果中不爲0的值的XY方向的梯度,利用梯度累加斜率指定直線上的沒一個點(斜率爲指定最大值和最小值之間的距離),最後標記邊緣圖像中每個非零像素的位置.,從二維累加器中選擇候選中心.
霍夫圓變換的缺陷在於閾值設置若是比較低,那麼算法消耗時間長,同心圓的間隔比較近的時候,傾向於保存半徑最大的圓,而且霍夫梯度法在某些時候也會產生噪聲.
API:void houghCircles(源圖,結果向量,int 檢測方法,int 輸入圖像和累加器的分辨率之比,int 圓心之間最小距離,double 算法高閾值,低閾值默認爲高閾值1/2,double 圓心累累加器閾值,int 半徑最小值,int 半徑最大值);
注:源圖像爲八位單通道灰度圖,目標向量爲vecter<vec3f>,向量中存儲的依次是圓心x,圓心y,半徑r,檢測方法目前只有霍夫梯度法HOUGH_GRENIENT ,霍夫梯度法默認高閾值100.低閾值爲其1/2,圓心間距過小,多個相鄰的圓會重合,太大,某些圓不能被檢測出,累加器閾值過小,會檢測出不少不存在的圓,閾值越大,越容易檢測出完美的圓
另外,函數可能找不到合適的半徑供用戶使用,能夠忽略半徑,用額外的步驟肯定.
使用例程
Mat srcImage,srcGrayImage; vector<Vec3f>circles; //圓2形?最Á?小?距¨¤離¤? const int g_houghcircleMinDistMax = 39; int g_houghcircleMinDistValue; void onTrackBarMinDist(int pos,void* userData); //canny算?子Á¨®高?閾D值¦Ì const int g_houghcircleThresholdUpMax = 254; int g_houghcircleThresholdUpValue; void onTrackBarThresholdUp(int pos,void* userData); //圓2心?累¤?加¨®器¡Â閾D值¦Ì const int g_houghcircleCenterThresholdMax = 254; int g_houghcircleCenterThresholdValue; void onTrackBarCenterThreshold(int pos,void* userData); //最Á?小?半ã?徑? const int g_houghcircleMinRadiusMax = 200; int g_houghcircleMinRadiusValue; void onTrackBarRadiusMin(int pos,void* userData); //最Á?大䨮半ã?徑? const int g_houghcircleMaxRadiusMax = 1000; int g_houghcircleMaxRadiusValue; void onTrackBarRadiusMax(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\HoughCircle.jpg"); if(srcImage.channels() == 3) { cvtColor(srcImage, srcGrayImage, CV_RGB2GRAY); } else { srcGrayImage = srcImage.clone(); } namedWindow("src gray image"); namedWindow("dst image"); g_houghcircleMinDistValue = 9; g_houghcircleThresholdUpValue = 199; g_houghcircleCenterThresholdValue = 99; g_houghcircleMinRadiusValue = 39; g_houghcircleMaxRadiusValue = 399; createTrackbar("center min dist", "dst image", &g_houghcircleMinDistValue, g_houghcircleMinDistMax,onTrackBarMinDist,0); createTrackbar("canny threshold", "dst image", &g_houghcircleThresholdUpValue, g_houghcircleThresholdUpMax,onTrackBarThresholdUp,0); createTrackbar("center threshold", "dst image", &g_houghcircleCenterThresholdValue, g_houghcircleCenterThresholdMax,onTrackBarCenterThreshold,0); createTrackbar("min radius", "dst image", &g_houghcircleMinRadiusValue, g_houghcircleMinRadiusMax,onTrackBarRadiusMin,0); createTrackbar("max radius", "dst image", &g_houghcircleMaxRadiusValue, g_houghcircleMaxRadiusMax,onTrackBarRadiusMax,0); onTrackBarRadiusMin(g_houghcircleMinDistValue,0); imshow("src gray image", srcGrayImage); moveWindow("src gray image", 0, 0); moveWindow("dst image", srcGrayImage.cols, 0); waitKey(0); return 0; } void onTrackBarMinDist(int pos,void* userData) { int minDist = g_houghcircleMinDistValue+1; double cannyThreshold = (double)g_houghcircleThresholdUpValue+1; double centerThreshold = (double)g_houghcircleCenterThresholdValue+1; int minRadius = g_houghcircleMinRadiusValue+1; int maxRadius = g_houghcircleMaxRadiusValue+1; if(minRadius >= maxRadius) { imshow("dst image", srcGrayImage); } else { Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, 1, minDist,cannyThreshold,centerThreshold,minRadius,maxRadius); for (size_t i = 0; i < circles.size(); i++) { circle(dstImage, Point(circles[i][0],circles[i][1]), circles[i][2], Scalar(0,0,255)); } imshow("dst image", dstImage); } } void onTrackBarThresholdUp(int pos,void* userData) { int minDist = g_houghcircleMinDistValue+1; double cannyThreshold = (double)g_houghcircleThresholdUpValue+1; double centerThreshold = (double)g_houghcircleCenterThresholdValue+1; int minRadius = g_houghcircleMinRadiusValue+1; int maxRadius = g_houghcircleMaxRadiusValue+1; if(minRadius >= maxRadius) { imshow("dst image", srcGrayImage); } else { Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, 1, minDist,cannyThreshold,centerThreshold,minRadius,maxRadius); for (size_t i = 0; i < circles.size(); i++) { circle(dstImage, Point(circles[i][0],circles[i][1]), circles[i][2], Scalar(0,0,255),LINE_AA); } imshow("dst image", dstImage); } } void onTrackBarCenterThreshold(int pos,void* userData) { int minDist = g_houghcircleMinDistValue+1; double cannyThreshold = (double)g_houghcircleThresholdUpValue+1; double centerThreshold = (double)g_houghcircleCenterThresholdValue+1; int minRadius = g_houghcircleMinRadiusValue+1; int maxRadius = g_houghcircleMaxRadiusValue+1; if(minRadius >= maxRadius) { imshow("dst image", srcGrayImage); } else { Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, 1, minDist,cannyThreshold,centerThreshold,minRadius,maxRadius); for (size_t i = 0; i < circles.size(); i++) { circle(dstImage, Point(circles[i][0],circles[i][1]), circles[i][2], Scalar(0,0,255)); } imshow("dst image", dstImage); } } void onTrackBarRadiusMax(int pos,void* userData) { int minDist = g_houghcircleMinDistValue+1; double cannyThreshold = (double)g_houghcircleThresholdUpValue+1; double centerThreshold = (double)g_houghcircleCenterThresholdValue+1; int minRadius = g_houghcircleMinRadiusValue+1; int maxRadius = g_houghcircleMaxRadiusValue+1; if(minRadius >= maxRadius) { imshow("dst image", srcGrayImage); } else { Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, 1, minDist,cannyThreshold,centerThreshold,minRadius,maxRadius); for (size_t i = 0; i < circles.size(); i++) { circle(dstImage, Point(circles[i][0],circles[i][1]), circles[i][2], Scalar(0,0,255)); } imshow("dst image", dstImage); } } void onTrackBarRadiusMin(int pos,void* userData) { int minDist = g_houghcircleMinDistValue+1; double cannyThreshold = (double)g_houghcircleThresholdUpValue+1; double centerThreshold = (double)g_houghcircleCenterThresholdValue+1; int minRadius = g_houghcircleMinRadiusValue+1; int maxRadius = g_houghcircleMaxRadiusValue+1; if(minRadius >= maxRadius) { imshow("dst image", srcGrayImage); } else { Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(0,0,0)); HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, 1, minDist,cannyThreshold,centerThreshold,minRadius,maxRadius); for (size_t i = 0; i < circles.size(); i++) { circle(dstImage, Point(circles[i][0],circles[i][1]), circles[i][2], Scalar(0,0,255)); } imshow("dst image", dstImage); } }
四.重映射
重映射是指將一張圖片上的某個指定位置的像素拷貝到目標圖像的某一個位置上
API:void remap(源圖,目的圖,映射數組1,映射數組2,int 插值方式,int 邊界模式,int 邊界值)
注:源和目標都必須爲八位單通道圖像或者浮點單通道圖像
使用例程
int main(int argc,char* argv[]) { Mat srcImage,mapx,mapy,dstImage; srcImage = imread("F:\\opencv\\OpenCVImage\\remap.jpg"); mapx.create(srcImage.size(), CV_32FC1); mapy.create(srcImage.size(), CV_32FC1); dstImage.create(srcImage.rows, srcImage.cols, srcImage.type()); //核?心?就¨ª是º?這a個?mapx 和¨ªmapy for(int j = 0; j < srcImage.rows;j++) { for (int i = 0; i < srcImage.cols; i++) { mapx.at<float>(j,i) = static_cast<float>(i); mapy.at<float>(j,i) = static_cast<float>(srcImage.rows-j); } } remap(srcImage, dstImage, mapx, mapy, INTER_LINEAR,BORDER_CONSTANT,Scalar(0,0,0)); imshow("src image", srcImage); imshow("dst image", dstImage); moveWindow("src image", 0, 0); moveWindow("dst image", srcImage.cols, 0); waitKey(0); return 0; }
五.仿射變換
集合中,一個向量空間進行一次線性變換並加上那個一次平移,變成另外一個向量空間,叫作仿射變換,一個任意的仿射變換均可以表示成乘以一個矩陣,再加上一個向量的形式,
仿射變換能夠實現圖片的縮放,旋轉,平移,其表明的是兩張圖片之間的映射關係.
API:void warpAffine(源圖像,目標圖像,變換矩陣,Size 輸出圖像尺寸,int 插值方式,int 邊界模式,int 恆定邊界取值)
注:源可使多通道或者單通道,目標和源的類型一致,變換矩陣通常來講能夠經過getRotationMatrix2D來得到,而不須要本身去實現.得到的是一個2*3的變換矩陣,插值方式默認爲INTER_LINEAR,和RESIZE插值方式類似,可是又添加了兩種新的插值方式,CV_WARP_FILL_OUTLIERS填充全部輸出圖像的像素,CV_WARP_INVERSE_MAP代表該變換試一次輸出圖像到輸入圖像的逆變換.
API Mat getRotationMatrix2D(Point源圖的旋轉中心,double 旋轉角度,double 縮放係數)
注:該API反悔的矩陣能夠做爲仿射變換的變換矩陣使用
使用代碼實際例程以下
Mat srcImage,dstImage,rotationImage; const int g_angelMax = 360; int g_angelValue; void onTrackBarRotationAngel(int pos,void* userData); const int g_scaleMax = 10;//最Á?大䨮10倍À?縮?放¤?系¦Ì數ºy int g_scaleValue; void onTrackBarScale(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\warpAffine.jpg"); namedWindow("src image"); namedWindow("dst image"); g_angelValue = 0; g_scaleValue = 1; createTrackbar("angel value", "dst image", &g_angelValue, g_angelMax,onTrackBarRotationAngel,0); createTrackbar("scale value", "dst image", &g_scaleValue, g_scaleMax,onTrackBarScale,0); onTrackBarRotationAngel(g_angelValue,0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("dst image", srcImage.cols, 0); waitKey(0); return 0; } void onTrackBarRotationAngel(int pos,void* userData) { if(g_scaleValue == 0)g_scaleValue = 1; double scale = 1.0/g_scaleValue; rotationImage = getRotationMatrix2D(Point(srcImage.cols/2,srcImage.rows/2), g_angelValue, scale); warpAffine(srcImage, dstImage, rotationImage, srcImage.size(),INTER_LINEAR); imshow("dst image", dstImage); } void onTrackBarScale(int pos,void* userData) { if(g_scaleValue == 0)g_scaleValue = 1; double scale = 1.0/g_scaleValue; rotationImage = getRotationMatrix2D(Point(srcImage.cols/2,srcImage.rows/2), g_angelValue, scale); warpAffine(srcImage, dstImage, rotationImage, srcImage.size(),INTER_LINEAR); imshow("dst image", dstImage); }
六.直方圖均衡化
若是須要擴大圖像的動態範圍,最常使用的技術就是直方圖均衡化,屬於弧度變幻的一個重要應用,用必定的算法,使直方圖大體平和的過程.拉伸像素強度的分佈範圍來加強圖像的對比度,例如原先圖像的像素灰度集中的100-200區域,那麼將100-200區域的數據擴展到0-255,就屬於直方圖均衡化.
均衡化之後的圖像只能近似的均勻分佈,動態範圍擴大,本質是擴大了量化間距,而量化級別反而減小了.這是一個缺點,均衡化之後可能會出現僞輪廓,或者消除原來圖像的有效輪廓.
在泛白緩和的圖像中,均衡化會合並一些像素灰度,從而增大對比度
原始圖像對比度本省就比較高的,在均衡化會形成灰度調和,從而下降對比度
從色彩上說,均衡化會是圖像的表現力更出色.
API:void equalizeHist(源圖像,目標圖像)
源和目標,都必須爲八位單通道圖像
使用實例
int main(int argc,char* argv[]) { Mat srcImage,dstImage; srcImage = imread("F:\\opencv\\OpenCVImage\\equalizeHist.jpg"); if(srcImage.channels() != 1) { cvtColor(srcImage, srcImage, CV_RGB2GRAY); } equalizeHist(srcImage, dstImage); //Mat dstRgbImage(srcImage.rows,srcImage.cols,CV_8UC3); //cvtColor(dstImage, dstRgbImage, CV_GRAY2BGR); imshow("src image", srcImage); imshow("dst image", dstImage); moveWindow("src image", 0, 0); moveWindow("dst image", srcImage.cols, 0); waitKey(0); return 0; }