OpenCV学习(8)
OpenCV仿射变换
1 int warpExample(void) { 2 // OpenCV仿射变换 3 // T = M × X 4 cv::Point2f srcTri[3]; 5 cv::Point2f dstTri[3]; 6 cv::Mat rotMat(2, 3, CV_32FC1); 7 cv::Mat warpMat(2, 3, CV_32FC1); 8 cv::Mat src, warpDst, warpRotateDst; 9 src = cv::imread("dog.jpg", cv::IMREAD_COLOR); 10 11 if (src.empty()) 12 return -1; 13 14 warpDst = cv::Mat::zeros(src.rows, src.cols, src.type()); 15 srcTri[0] = cv::Point2f(0, 0); 16 srcTri[1] = cv::Point2f(src.cols - 1.f, 0); 17 srcTri[2] = cv::Point2f(0, src.cols - 1.f); 18 dstTri[0] = cv::Point2f(src.cols * 0.0f, src.rows * 0.33f); 19 dstTri[1] = cv::Point2f(src.cols * 0.85f, src.rows * 0.25f); 20 dstTri[2] = cv::Point2f(src.cols * 0.15f, src.rows * 0.7f); 21 22 // 通过3点对应关系获得反射变换矩阵 23 // https://blog.csdn.net/claroja/article/details/83624701 24 warpMat = cv::getAffineTransform(srcTri, dstTri); 25 // 仿射变换 26 // https://www.xuebuyuan.com/509229.html 27 cv::warpAffine(src, warpDst, warpMat, warpDst.size()); 28 29 cv::Point center = cv::Point(warpDst.cols / 2, warpDst.rows / 2); 30 double angle = -50.0; 31 double scale = 0.6; 32 33 // 获得仿射变化矩阵 参数:中心点 旋转角度 缩放比例 34 rotMat = cv::getRotationMatrix2D(center, angle, scale); 35 cv::warpAffine(warpDst, warpRotateDst, rotMat, warpDst.size()); 36 cv::namedWindow("Src", cv::WINDOW_AUTOSIZE); 37 cv::imshow("Src", src); 38 cv::namedWindow("Warp", cv::WINDOW_AUTOSIZE); 39 cv::imshow("Warp", warpDst); 40 cv::namedWindow("WarpRotate", cv::WINDOW_AUTOSIZE); 41 cv::imshow("WarpRotate", warpRotateDst); 42 // 展示了通过两种不同的方式获取仿射矩阵 在对图像作仿射变换 43 44 cv::waitKey(0); 45 return 0; 46 }
图像直方图与其均衡化
int equalizeHistExample(void) { // 图像直方图与其均衡化 cv::Mat src = cv::imread("dog.jpg", cv::IMREAD_COLOR); if (src.empty()) return -1; cv::Mat dst; cv::cvtColor(src, src, cv::COLOR_BGR2GRAY); // 图像直方图均衡化 cv::equalizeHist(src, dst); cv::namedWindow("Src", cv::WINDOW_AUTOSIZE); cv::namedWindow("Dst", cv::WINDOW_AUTOSIZE); // 可以看到图像对比度增强的了 cv::imshow("Src", src); cv::imshow("Dst", dst); cv::waitKey(0); return 0; } int calcHistExample(void) { // 图像直方图的计算 绘制出直方图 cv::Mat src, dst; src = cv::imread("dog.jpg", cv::IMREAD_COLOR); if (src.empty()) return -1; vector<cv::Mat> bgrPlanes; // 图像通道的分离 cv::split(src, bgrPlanes); int histSize = 256; float range[] = { 0, 256 }; const float* histRange = { range }; bool uniform = true; bool accumulate = false; cv::Mat bHist, gHist, rHist; // 直方图的计算 // https://blog.csdn.net/shuiyixin/article/details/80032167 cv::calcHist(&bgrPlanes[0], 1, 0, cv::Mat(), bHist, 1, &histSize, &histRange, uniform, accumulate); cv::calcHist(&bgrPlanes[1], 1, 0, cv::Mat(), gHist, 1, &histSize, &histRange, uniform, accumulate); cv::calcHist(&bgrPlanes[2], 1, 0, cv::Mat(), rHist, 1, &histSize, &histRange, uniform, accumulate); // 绘制图像直方图 int histW = 512, histH = 400; // cvRound返回跟参数最接近的整数值,即四舍五入 https://blog.csdn.net/sinat_36264666/article/details/78849125 int binW = cvRound((double)histW / histSize); cv::Mat histImage(histH, histW, CV_8UC3, cv::Scalar(0, 0, 0)); cv::normalize(bHist, bHist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); cv::normalize(gHist, gHist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); cv::normalize(rHist, rHist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); // 绘制直方图 一点没有Python方便 for (int i = 1; i < histSize; i++) { cv::line(histImage, cv::Point(binW * (i - 1), histH - cvRound(bHist.at<float>(i - 1))), cv::Point(binW * (i), histH - cvRound(bHist.at< float>(i))), cv::Scalar(255, 0, 0), 2, 8, 0); cv::line(histImage, cv::Point(binW * (i - 1), histH - cvRound(gHist.at<float>(i - 1))), cv::Point(binW * (i), histH - cvRound(gHist.at< float>(i))), cv::Scalar(0, 255, 0), 2, 8, 0); cv::line(histImage, cv::Point(binW * (i - 1), histH - cvRound(rHist.at<float>(i - 1))), cv::Point(binW * (i), histH - cvRound(rHist.at< float>(i))), cv::Scalar(0, 0, 255), 2, 8, 0); } cv::namedWindow("calcHist Demo", cv::WINDOW_AUTOSIZE); cv::imshow("calcHist Demo", histImage); cv::waitKey(0); return 0; }
1 int compareHistExample(void) { 2 cv::Mat srcBase, hsvBase; 3 cv::Mat srcTest1, hsvTest1; 4 cv::Mat srcTest2, hsvTest2; 5 cv::Mat hsvHalfDown; 6 7 srcBase = cv::imread("sky1.jpg", cv::IMREAD_COLOR); 8 srcTest1 = cv::imread("sky2.jpg", cv::IMREAD_COLOR); 9 srcTest2 = cv::imread("sky3.jpg", cv::IMREAD_COLOR); 10 11 // if () 12 cv::cvtColor(srcBase, hsvBase, cv::COLOR_BGR2HSV); 13 cv::cvtColor(srcTest1, hsvTest1, cv::COLOR_BGR2HSV); 14 cv::cvtColor(srcTest2, hsvTest2, cv::COLOR_BGR2HSV); 15 16 hsvHalfDown = hsvBase(cv::Range(hsvBase.rows / 2, hsvBase.rows - 1), cv::Range(0, hsvBase.cols - 1)); 17 int hBins = 50, sBins = 60; 18 int histSize[] = { hBins, sBins }; 19 float hRanges[] = { 0, 180 }; 20 float sRanges[] = { 0, 256 }; 21 const float* ranges[] = { hRanges, sRanges }; 22 23 int channels[] = { 0, 1 }; 24 cv::MatND histBase, histHalfDown, histTest1, histTest2; 25 26 cv::calcHist(&hsvBase, 1, channels, cv::Mat(), histBase, 2, histSize, ranges, true, false); 27 cv::normalize(histBase, histBase, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 28 29 cv::calcHist(&hsvHalfDown, 1, channels, cv::Mat(), hsvHalfDown, 2, histSize, ranges, true, false); 30 cv::normalize(histHalfDown, histHalfDown, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 31 32 cv::calcHist(&hsvTest1, 1, channels, cv::Mat(), hsvTest1, 2, histSize, ranges, true, false); 33 cv::normalize(histTest1, histTest1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 34 35 cv::calcHist(&hsvTest2, 1, channels, cv::Mat(), hsvTest2, 2, histSize, ranges, true, false); 36 cv::normalize(histTest2, histTest2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 37 38 for (int i = 0; i < 4; i++) { 39 int compareMethod = i; 40 double baseBase = cv::compareHist(histBase, histBase, compareMethod); 41 double baseHalf = cv::compareHist(histBase, histHalfDown, compareMethod); 42 double baseTest1 = cv::compareHist(histBase, histTest1, compareMethod); 43 double baseTest2 = cv::compareHist(histBase, histTest2, compareMethod); 44 45 printf("Method [%d] Perfect, Base-Half, Base-Test1, Base-Test2 : %f, %f, %f, %f \n", i, baseBase, baseHalf, baseTest1, baseTest2); 46 } 47 48 cv::waitKey(0); 49 return 0; 50 }
OpenCV反向投影
1 cv::Mat src, hsv, hue; 2 int bins = 25; 3 4 void HistAndBackproj(int, void*) { 5 cv::MatND hist; 6 int histSize = MAX(bins, 2); 7 float hueRange[] = { 0, 180 }; 8 const float* ranges = { hueRange }; 9 cv::calcHist(&hue, 1, 0, cv::Mat(), hist, 1, &histSize, &ranges, true, false); 10 cv::normalize(hist, hist, 0, 255, cv::NORM_MINMAX, -1, cv::Mat()); 11 cv::MatND backproj; 12 // 创建反向投影 13 cv::calcBackProject(&hue, 1, 0, hist, backproj, &ranges, 1, true); 14 cv::imshow("BackProj", backproj); 15 int w = 400, h = 400; 16 int binW = cvRound((double)2 / histSize); 17 cv::Mat histImage = cv::Mat::zeros(w, h, CV_8UC3); 18 for (int i = 0; i < bins; i++) { 19 cv::rectangle(histImage, cv::Point(i * binW, h), cv::Point((i + 1) * binW, h - cvRound(hist.at<float>(i) * h / 255.0)), cv::Scalar(0, 0, 255), -1); 20 } 21 cv::imshow("Histogram", histImage); 22 } 23 24 int main(void) { 25 // OpenCV反向投影 26 src = cv::imread("hand1.png", cv::IMREAD_COLOR); 27 if (src.empty()) 28 return -1; 29 30 cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV); 31 hue.create(hsv.size(), hsv.depth()); 32 int ch[] = { 0, 0 }; 33 // 把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)的某些通道中,其中的对应关系就由fromTo参数制定 34 cv::mixChannels(&hsv, 1, &hue, 1, ch, 1); 35 cv::createTrackbar("* Hue bins: ", "Source image", &bins, 180, HistAndBackproj); 36 HistAndBackproj(0, 0); 37 cv::imshow("Source image", src); 38 39 cv::waitKey(0); 40 return 0; 41 }
模板匹配
1 bool useMask; 2 cv::Mat img, templ, mask, result; 3 const char* imageWindow = "Source Image"; 4 const char* resultWindow = "Result Image"; 5 int matchMethod; 6 int maxTrackbar = 5; 7 8 void MatchingMethod(int, void*) { 9 cv::Mat imgDisplay; 10 img.copyTo(imgDisplay); 11 int resultCols = img.cols - templ.cols + 1; 12 int resultRows = img.rows - templ.rows + 1; 13 result.create(result.rows, result.cols, CV_32FC1); 14 bool methodAcceptsMask = (CV_TM_SQDIFF == matchMethod || matchMethod == CV_TM_CCOEFF_NORMED); 15 if (useMask && methodAcceptsMask) { 16 // 用于模板匹配 17 cv::matchTemplate(img, templ, result, matchMethod, mask); 18 } 19 else { 20 cv::matchTemplate(img, templ, result, matchMethod); 21 } 22 23 cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 24 double minVal, maxVal; 25 cv::Point minLoc, maxLoc, matchLoc; 26 // minMaxLoc寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置. 27 cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat()); 28 if (matchMethod == CV_TM_SQDIFF || matchMethod == CV_TM_SQDIFF_NORMED) 29 matchLoc = minLoc; 30 else 31 matchLoc = maxLoc; 32 cv::rectangle(imgDisplay, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar::all(0), 2, 8, 0); 33 cv::rectangle(result, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar::all(0), 2, 8, 0); 34 cv::imshow(imageWindow, imgDisplay); 35 cv::imshow(resultWindow, result); 36 } 37 38 int main(void) { 39 // 模板匹配 40 // 查找与模板图像匹配的图像区域 41 img = cv::imread("Lisa.png", cv::IMREAD_COLOR); 42 templ = cv::imread("LisaFace.png", cv::IMREAD_COLOR); 43 44 if (img.empty() || templ.empty()) 45 return -1; 46 47 cv::createTrackbar("Method: \n 0; SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED", imageWindow, &matchMethod, maxTrackbar, MatchingMethod); 48 MatchingMethod(0, 0); 49 50 cv::waitKey(0); 51 return 0; 52 }
图像中查找轮廓
1 cv::Mat src, srcGray; 2 int thresh = 100; 3 int maxThresh = 255; 4 cv::RNG rng(12345); 5 6 void threshCallback(int, void*) { 7 cv::Mat cannyOutput; 8 vector<vector<cv::Point>> contours; // 轮廓 9 vector<cv::Vec4i> hierarchy; 10 cv::Canny(srcGray, cannyOutput, thresh, thresh * 2, 3); // 边缘检测 11 // https://blog.csdn.net/guduruyu/article/details/69220296 12 // 函数cv::findContour是从二值图像中来计算轮廓的,它可以使用cv::Canny()函数处理的图像,因为这样的图像含有边缘像素; 13 // 也可以使用cv::threshold()或者cv::adaptiveThreshold()处理后的图像,其边缘隐含在正负区域的交界处。 14 cv::findContours(cannyOutput, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0)); 15 cv::Mat drawing = cv::Mat::zeros(cannyOutput.size(), CV_8UC3); 16 17 for (size_t i = 0; i < contours.size(); i++) { 18 cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); // 随机选取颜色 19 // 画出边缘曲线 20 cv::drawContours(drawing, contours, (int)i, color, 2, 8, hierarchy, 0, cv::Point()); 21 } 22 23 cv::namedWindow("Contours", cv::WINDOW_AUTOSIZE); 24 cv::imshow("Contours", drawing); 25 } 26 27 28 int main(void) { 29 // 图像中查找轮廓 30 src = cv::imread("bowl.jpg", cv::IMREAD_ANYCOLOR); 31 if (src.empty()) 32 return -1; 33 34 cv::cvtColor(src, srcGray, cv::COLOR_BGR2GRAY); 35 cv::blur(srcGray, srcGray, cv::Size(3, 3)); 36 cv::namedWindow("Source", cv::WINDOW_AUTOSIZE); 37 cv::imshow("Source", src); 38 cv::createTrackbar("Canny thresh:", "Source", &thresh, maxThresh, threshCallback); 39 threshCallback(0, 0); 40 41 cv::waitKey(0); 42 return 0; 43 }
1 cv::Mat src, srcGray; 2 int thresh = 100; 3 int maxThresh = 255; 4 cv::RNG rng(12345); 5 6 void threshCallback(int, void*) { 7 cv::Mat thresholdOutput; 8 vector<vector<cv::Point>> contours; // 轮廓 9 vector<cv::Vec4i> hierarchy; 10 // 使用threshold进行边缘检测 11 cv::threshold(srcGray, thresholdOutput, thresh, 255, cv::THRESH_BINARY); 12 cv::findContours(thresholdOutput, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0)); 13 vector<vector<cv::Point>> contoursPoly(contours.size()); 14 vector<cv::Rect> boundRect(contours.size()); 15 vector<cv::Point2f> center(contours.size()); 16 vector<float> radius(contours.size()); 17 18 for (size_t i = 0; i < contours.size(); i++) { 19 // approxPolyDP 主要功能是把一个连续光滑曲线折线化,对图像轮廓点进行多边形拟合。 20 // https://blog.csdn.net/kakiebu/article/details/79824856 21 cv::approxPolyDP(cv::Mat(contours[i]), contoursPoly[i], 3, true); 22 // 计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的 参数是轮廓的点集 23 boundRect[i] = cv::boundingRect(cv::Mat(contoursPoly[i])); 24 // 计算最小包围圆 25 cv::minEnclosingCircle(contoursPoly[i], center[i], radius[i]); 26 } 27 28 cv::Mat drawing; 29 for (size_t i = 0; i < contours.size(); i++) { 30 cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); 31 cv::drawContours(drawing, contoursPoly, (int)i, color, 1, 8, vector<cv::Vec4i>(), 0, cv::Point()); 32 cv::rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0); 33 cv::circle(drawing, center[i], (int)radius[i], color, 2, 8, 0); 34 } 35 36 cv::namedWindow("Contours", cv::WINDOW_AUTOSIZE); 37 cv::imshow("Contours", drawing); 38 } 39 40 int main(void) { 41 // 为轮廓创建边界框和圆 42 src = cv::imread("balloon.jpg", cv::IMREAD_ANYCOLOR); 43 if (src.empty()) 44 return -1; 45 46 cv::cvtColor(src, srcGray, cv::COLOR_BGR2GRAY); 47 cv::blur(srcGray, srcGray, cv::Size(3, 3)); 48 cv::namedWindow("Source", cv::WINDOW_AUTOSIZE); 49 cv::imshow("Source", src); 50 cv::createTrackbar("Canny thresh:", "Source", &thresh, maxThresh, threshCallback); 51 threshCallback(0, 0); 52 53 cv::waitKey(0); 54 return 0; 55 }
转载请注明出处