上传一下一直记在有道云笔记里的东西
××——2017.11.3
目前已经可以实现
1.打开摄像头显示画面
2.使用cvtColor()将画面由BGR转为HSV
3.分割图像,保留红色像素
4.形态学运算膨胀图像(dilate) 使红色更明显
5.利用hough,变换提取图像中的圆形
6.绘制圆形
问题:
但事实证明用霍夫变换是不对的
霍夫变换只能识别边界明确的圆形
而实际的球周围有许多彩带干扰有可能导致难以识别完整的圆边界
用Circle绘制的圆形轮廓也不太正确
需要重新编写能生成包围整个球的圆形轮廓
2017-11-4
今日完成:
1.使用吸管工具吸取黄球照片中的16个不同程度的黄色,
使用取色软件Pipette得到HSV数值范围
(再结合实际摄像头测试,这种方法得到的颜色范围数据还是无法分割出绣球黄色部分,
最后还是一次次测试最后手动调成功的较为准确的HSV数值范围, Scalar(15, 60, 150), Scalar(45, 255, 255),写入程序中)
进而可以将识别官方黄球颜色,并在画面中分割出黄色部分
2.使用dilate()使黄色区域更加明显,element SIZE为10
3.使用Threshold检测边缘,阈值为5,findContours找出轮廓,并绘制最小面积包围圆形,
问题:
1.距离越近彩带的干扰越大,需要对图像进一步处理
2.目前只能识别一种颜色的球
2017-11-5
今日完成:
1.加了均值滤波去噪,element SIZE(20,20)
2.将膨胀改为闭运算,可以消除目标不连续空洞,element SIZE(40,40),使绣球的轮廓更清晰
均值滤波核为5时:
均值滤波核为20时:
由此可见,20时可以较大减少彩带的干扰
接下来要尝试获取绣球的位置信息
3.计算轮廓矩和质心并显示坐标,左上角为坐标原点
4.干扰太多,需要想办法只显示绣球坐标
使用if(area > 150){ }的方法剔除了小面积轮廓
因为实验室的任务变更,就没有继续优化这个代码了,目前为止的代码在下面贴一下
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
RNG g_rng(12345);
int main(int argc, char** argv)
{
VideoCapture sensor(1); //capture the video from web cam
if ( !sensor.isOpened() ) // if not success, exit program
{
cout << "Cannot open the web cam" << endl;
return -1;
}
while (true)
{
Mat frameOriginal;
bool bSuccess = sensor.read(frameOriginal); // read a new frame from video
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read a frame from video stream" << endl;
break;
}
Mat frameHSV;
vector<Mat> hsvSplit;
cvtColor(frameOriginal, frameHSV, COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV
Mat frameThresholded;
inRange(frameHSV, Scalar(15, 60, 150), Scalar(45, 255, 255), frameThresholded); //Threshold the image
//均值滤波去噪
Mat frameBLUR;
blur(frameThresholded, frameBLUR, Size(20, 20), Point(-1, -1));
//闭运算消除目标不连续空洞
Mat element= getStructuringElement(MORPH_RECT,Size(40,40));
Mat frameCLOSE;
morphologyEx(frameBLUR, frameCLOSE, MORPH_CLOSE, element);
//定义一些参数
Mat threshold_output;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
// 使用Threshold检测边缘
threshold( frameThresholded, threshold_output, 5, 255, THRESH_BINARY );
// 找出轮廓
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
//计算轮廓矩
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
mu[i] = moments( contours[i], false );
}
//计算轮廓的质心
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
mc[i] = Point2d( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 );
}
// 直接使用CONTOUR中的矩形来画轮廓
int order = 1;
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( 255, 0, 0);
double area = mu[i].m00;//面积
Rect ret1 = boundingRect(Mat(contours[i])); //获取目标序列号放置位置
if(area > 150) //剔除小面积轮廓
{
drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
circle( drawing, mc[i], 5, Scalar( 0, 0, 255), -1, 8, 0 );
rectangle(drawing, boundingRect(contours.at(i)), cvScalar(0,255,0));
char tam[100];
sprintf(tam, "(%0.0f,%0.0f)",mc[i].x,mc[i].y);
putText(drawing, tam, Point(mc[i].x, mc[i].y), FONT_HERSHEY_SIMPLEX, 0.8, cvScalar(255,0,255),1);
char tam1[100];
sprintf(tam1, "%d",order++);
putText(drawing, tam1, Point(ret1.x+ret1.width, ret1.y+ret1.height), FONT_HERSHEY_SIMPLEX, 0.3, cvScalar(0,255,255),1);
}
}
imshow("Original", frameOriginal);
imshow("Out", drawing);
char key = (char) waitKey(300);
if(key == 27)
break;
}
return 0;
}