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 }