开通了我的博客,第一次写文章,目的是用于自己保存学习的过程和大家一起交流,可能会有些不专业或者有错的地方,还望路过的大神们指出。
先上两张图。魔方是菲神创纪录时用的品牌GAN,花了我六十几RMB,手感果然和十几块钱的妖艳贱货不一样。
首先我想到的就是先边缘检测,然后开始遍历,找到坐上角的点和右下角的点,然后就可以算出中点。这么简单,想想还有点小激动呢。
Point find_heart(Mat src) /*找到魔方的中心点*/
{
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
Mat dst = src.clone();
cvtColor(src,src, COLOR_BGR2GRAY); //将BGR图像转为单通道灰度图
bilateralFilter( src, dst, 8, 16, 5); //双边滤波,保边去噪
//cvtColor(dst, dst , COLOR_BGR2GRAY); //将BGR图像转为单通道灰度图
Mat element = getStructuringElement(MORPH_RECT, Size(2, 2));
Canny(dst, dst, 60, 70); //边缘检测
imshow("show",dst);
waitKey(60);
for (int i = 0;i < 0.3*dst.cols;i++)
{
for (int j = 0;j < 0.3*dst.rows;j++)
{
if (dst.at<uchar>(i, j) == 255)
{
x1 = i;
y1 = j;
break;
}
}
if (dst.at<uchar>(i, y1) == 255)
{
break;
}
}
for (int i = dst.cols-10 ; i > 0.5*dst.cols;i--)
{
for (int j = dst.rows-10 ; j > 0.5*dst.rows;j--)
{
if (dst.at<uchar>(i, j) == 255)
{
x2 = i;
y2 = j;
break;
}
}
if (dst.at<uchar>(i, y2) == 255)
{
break;
}
}
return Point((x1 + x2) / 2, (y1 + y2) / 2);
}
代码如上,由于比较菜和刚接触opencv,就这段代码就调试了很很多次。遇到的问题和解决方法记一下:
1.访问像素点的值。灰度图用image.at<uchar>(x,y)就行了,BGR三通道访问每一个通道的话用image.at<Vec3b>[1或2或3]分别访问三个通道的值。
2.不知道我怎么得出来的一个结论,如果图像过大,用imshow("",1)显示不完全的话,后面从右下角(image.coles,image.cows)开始遍历的话会导致溢出而报错,天知道我是试了多少次才发现。
3.跳出两个循环,用了两个break而没用goto,不知道是哪个老师给我说过,千万不要轻易的用goto。
后面又查了点资料,发现用指针遍历更好,所以我改了一下这个代码。
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<stdlib.h>
#include<string>
using namespace cv;
using namespace std;
Point find_heart(Mat src);
int main()
{
Mat imgOriginal,imgOriginal_quarter;
imgOriginal = imread("魔方.jpg", 1);
resize(imgOriginal, imgOriginal_quarter, Size(imgOriginal.cols / 5, imgOriginal.rows / 5), 0, 0, INTER_AREA); //尺寸缩小到原图1/5
//namedWindow("show1",0);
imshow("show",imgOriginal_quarter);
waitKey(600);
Point selfLoc = find_heart(imgOriginal_quarter);
circle(imgOriginal_quarter, selfLoc, 8, Scalar(255, 255, 255));
imshow("show1", imgOriginal_quarter);
waitKey(60000);
return 0;
}
Point find_heart(Mat src) /*找到魔方的中心点*/
{
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
Mat dst = src.clone();
cvtColor(src,src, COLOR_BGR2GRAY); //将BGR图像转为单通道灰度图
bilateralFilter( src, dst, 8, 16, 5); //双边滤波,保边去噪
Mat element = getStructuringElement(MORPH_RECT, Size(2, 2));
Canny(dst, dst, 60, 70); //边缘检测
for (int j = 0;j< int(dst.rows*0.5);j = j + 11) //找到左上角的坐标并保存到(x1,y1)
{
uchar* data = dst.ptr<uchar>(j);
for (int i = 0;i < 0.25*dst.cols;i++)
{
if (data[i] == 255)
{
x1 = i;
break;
}
}
if (data[x1] == 255)
{
y1 = j;
break;
}
}
for (int j = int (dst.rows-1);j > int(dst.rows*0.5);j = j - 11) //找到右下角的坐标并保存到(x2,y2)
{
uchar* data = dst.ptr<uchar>(j);
for (int i = dst.cols;i > 0.75*dst.cols;i--)
{
if (data[i] == 255)
{
x2 = i;
break;
}
}
if (data[x2] == 255)
{
y2 = j;
break;
}
}
return Point((x1 + x2) / 2, (y1 + y2) / 2); //返回魔方中点的值
}
改过后看起来就要好一点了,有一点误差,但是在我的接受范围内,我就不想继续改了。
今天先写到这(第一次用这个,感觉有点不好用是怎么回事),就当开始了我的博客之旅。俗话说:万事开头难,中间难,结尾难。噫嘘唏!为了早日成为一名合格的老司机,下午还要去练车(对了,顺便恭喜我昨天满分通过科二)。