一、预期目标
如下图,要识别图中的国旗,然后框选出来,并且返回国旗的中心位置,效果如下:
彩色图像大小: (400,264)
目标中心位置: (225, 218)
二、准备工作
1、将下面的图像另存为在本地,命名为 findflag.jpg
2、新建Python文件 findflag.py,与图像保存在同一目录下。
三、开始编写代码
1、读取与显示图像
#include <stdio.h>
#include <opencv-3.3.1-dev/opencv2/core.hpp>
#include <opencv-3.3.1-dev/opencv/highgui.h>
#include <opencv-3.3.1-dev/opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char **argv)
{
Mat img_bgr;
img_bgr = imread("/home/geng/test/flag.jpg");
imshow("Original Image", img_bgr);
waitKey(0);
return 0;
}
执行python findflag.py
,能够正常显示图像
注意OpenCV里面的图像矩阵为 BGR 格式,而不是 RGB
2、根据 HSV 获得目标
#include <stdio.h>
#include <opencv-3.3.1-dev/opencv2/core.hpp>
#include <opencv-3.3.1-dev/opencv/highgui.h>
#include <opencv-3.3.1-dev/opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char **argv)
{
Mat img_bgr;
img_bgr = imread("/home/geng/test/flag.jpg");
Mat img_hsv;
cvtColor(img_bgr,img_hsv, CV_BGR2HSV);
Mat img_flag;
inRange(img_hsv, Scalar(0,120,120), Scalar(10,255,255), img_flag);
imshow("Original Image", img_bgr);
imshow("Flag Image", img_flag);
waitKey(0);
waitKey(0);
return 0;
}
- 代码中,首先变化为 HSV 格式,因为 HSV 格式更利于做图像处理,具体原因可以参考RGB、HSV和HSL颜色空间。
- thresh1 的三个变量分别为 H(色度)、S(饱和度)、V(亮度)分量,[thresh1, thresh2] 之间的便是红旗的颜色。
- cv2.inRange(…) 返回一个图像矩阵(此处:256×400),大于阈值 thresh2 的为255(白色),小于阈值 thresh1 的为0(黑色),中间部分不变。
- cv2.bitwise_and(…) 函数是将图像进行与运算,使用来掩膜参数 mask,其效果相当于先把掩膜flag 和图像 img_hsv 相成,结果是除了红旗和噪声,其他地方为 0(黑色)。
红旗部分效果如下,可见成功提取到红旗部分,但是含有少量噪声。
3、图像滤波
#include <stdio.h>
#include <opencv-3.3.1-dev/opencv2/core.hpp>
#include <opencv-3.3.1-dev/opencv/highgui.h>
#include <opencv-3.3.1-dev/opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char **argv)
{
Mat img_bgr;
img_bgr = imread("/home/geng/test/flag.jpg");
Mat img_hsv;
cvtColor(img_bgr,img_hsv, CV_BGR2HSV);
Mat img_flag;
inRange(img_hsv, Scalar(0,120,120), Scalar(10,255,255), img_flag);
Mat img_morph;
int elem_type = MORPH_RECT;
Mat element = getStructuringElement(elem_type, Size(3,3), Point(1,1));
erode(img_flag, img_morph, element);
dilate(img_morph, img_morph, element);
imshow("Flag Image", img_flag);
imshow("Morph Image", img_morph);
waitKey(0);
waitKey(0);
return 0;
}
此处采用形态学(morphology)滤波算法,首先使用 (3×3)的核腐蚀 3次,然后又膨胀 3次,达到滤波效果,如下图:
4、特征显示
#include <opencv-3.3.1-dev/opencv2/core.hpp>
#include <opencv-3.3.1-dev/opencv/highgui.h>
#include <opencv-3.3.1-dev/opencv2/opencv.hpp>
#include <opencv-3.3.1-dev/opencv2/imgproc.hpp>
#include <opencv-3.3.1-dev/opencv2/imgcodecs.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char **argv)
{
Mat img_bgr;
img_bgr = imread("/home/geng/test/flag.jpg");
Mat img_hsv;
cvtColor(img_bgr,img_hsv, CV_BGR2HSV);
Mat img_flag;
inRange(img_hsv, Scalar(0,120,120), Scalar(10,255,255), img_flag);
Mat img_morph;
int elem_type = MORPH_RECT;
Mat element = getStructuringElement(elem_type, Size(3,3), Point(1,1));
erode(img_flag, img_morph, element);
dilate(img_morph, img_morph, element);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img_morph, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0,0));
vector<vector<Point> > contours_poly(1);
vector<Rect> boundRect(1);
int max_label = 0;
int max_area = 0;
for (size_t i=0; i<contours.size(); i++)
{
if (contours[i].size() > max_area)
{
max_area = contours[i].size();
max_label = i;
}
}
approxPolyDP( Mat(contours[max_label]), contours_poly[0], 3, true);
boundRect[0] = boundingRect( Mat(contours_poly[0]) );
Scalar color = Scalar(255, 0, 0);
vector<Point> aim_pos(2);
aim_pos[0] = boundRect[0].tl();
aim_pos[1] = boundRect[0].br();
cout << "彩色图像大小" << (img_bgr.cols) << ", " << (img_bgr.rows) << endl;
cout << "目标中心位置" << ((aim_pos[0].x + aim_pos[1].x) / 2) << ", " << ((aim_pos[0].y + aim_pos[1].y)/2) << endl;
rectangle(img_bgr, aim_pos[0], aim_pos[1], color, 2, 8, 0);
namedWindow("img_frame", WINDOW_AUTOSIZE);
imshow("img_frame", img_bgr);
waitKey(0);
return 0;
}
- 其中,cv2.findContours(…) 寻找轮廓,并建立一个等级树结构,记录的轮廓采用压缩值,例如一个矩形只用4点记录。返回各个轮廓只 cnts 中。
- 然后对各个轮廓从大到小排列,我们选择包含面积最大的轮廓(不一定是轮廓点数最多的),得出其最小外接矩形,这个矩形只用了 4 个点记录,如下图:
- 接下来计算目标图像中心并显示
- cv2.drawContours(img_bgr, [points], -1, (255,0,0), 2) 的意思是在图像 img_bgr 上叠加轮廓,轮廓为 points 构成的向量,-1:负数显示所有轮廓,填充颜色为蓝色,宽度为 2像素。
运行即可得到最终结果,如下:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)