OpenCV学习(三):⼀步步实现图像定位(ROSC++版)
⼀、预期⽬标
如下图,要识别图中的国旗,然后框选出来,并且返回国旗的中⼼位置,效果如下:
彩⾊图像⼤⼩: (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");// 需要下载图⽚到该⽬录下,也即 ~/test/flag.jpg,根据⾃⼰电脑修改路径imshow("Original Image", img_bgr);
waitKey(0);
return0;
}
执⾏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);
return0;
}
代码中,⾸先变化为 HSV 格式,因为 HSV 格式更利于做图像处理,具体原因可以参考。
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);
return0;
}
此处采⽤形态学(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>        // Add more .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);// The contour's points
vector<Rect>boundRect(1);
int max_label =0;// Find the max contour
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]));// The rectangle of the max contour
Scalar color =Scalar(255,0,0);
//drawContours(img_bgr, contours_poly, 0, color, 1, 8, vector<Vec4i>(), 0, Point());
vector<Point>aim_pos(2);
aim_pos[0]= boundRect[0].tl();
aim_pos[1]= boundRect[0].br();
cout <<"彩⾊图像⼤⼩"<<(ls)<<", "<<(ws)<< 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);
rectangle函数opencvreturn0;
}
其中,cv2.findContours(…) 寻轮廓,并建⽴⼀个等级树结构,记录的轮廓采⽤压缩值,例如⼀个矩形只⽤4点记录。返回各个轮廓只 cnts 中。
然后对各个轮廓从⼤到⼩排列,我们选择包含⾯积最⼤的轮廓(不⼀定是轮廓点数最多的),得出其最⼩外接矩形,这个矩形只⽤了 4个点记录,如下图:
接下来计算⽬标图像中⼼并显⽰
cv2.drawContours(img_bgr, [points], -1, (255,0,0), 2) 的意思是在图像 img_bgr 上叠加轮廓,轮廓为 points 构成的向量,-1:负数显⽰所有轮廓,填充颜⾊为蓝⾊,宽度为 2像素。
运⾏即可得到最终结果,如下:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。