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 
", 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: 
 0; SQDIFF 
 1: SQDIFF NORMED 
 2: TM CCORR 
 3: TM CCORR NORMED 
 4: TM COEFF 
 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 }
原文地址:https://www.cnblogs.com/lnlin/p/13815530.html