前言
导师给了一个任务,主要是在一张图片中识别出特定的图像,并标记出相应物体的位置(在坐标图上呈现),分别用c语言和matlab都实现一下来练手。
思路
参考了一些网上的代码,我这次实现的主要思路就是用鼠标获取目标图像中心点的像素值,并以这个点为中心扣出目标图像所在的图像块。
首先遍历原图的每个像素点,与 中心点 的像素值比较,如果原图 p点 像素值的差值在允许的范围内,则开始遍历图像块的第一个像素点(左上的点)以及以p点为中心的同样大小的图像块的第一个像素点(左上的点),如果图像块遍历完,每个像素点的差值都在允许范围内,则保存p点;如果任有一个像素点的差值过大,则遍历p点下一个点,继续与中心点比较像素值。
c语言代码
#include<opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include<iostream>
using namespace cv;
using namespace std;
Mat src;//原图,用来标点
Mat dst;//最后画圈所用的图
Mat ssrc;//中间呈现的图像块
int w = 13;
static Point pre_pt ;
static Point p;
vector<Point2f> vp;
int getSrcPixel(int x, int y)//遍历原图中的坐标点
{
//int G = (int)im.at<Vec3b>(3, 5)[2];//读取各点RGB的值
int sum = 0;
sum = (int)src.at<Vec3b>(x, y)[0] + (int)src.at<Vec3b>(x, y)[1] + (int)src.at<Vec3b>(x, y)[2];
return sum;
}
int getSsrcPixel(int x, int y)//遍历图像块的坐标点
{
int sum = 0;
sum = (int)ssrc.at<Vec3b>(x, y)[0] + (int)ssrc.at<Vec3b>(x, y)[1] + (int)ssrc.at<Vec3b>(x, y)[2];
return sum;
}
void judge()
{
int i = 0;
while (i<vp.size()-1)
{
if (vp[i].x == vp[i + 1].x)
if (vp[i].y + 1 == vp[i + 1].y || vp[i].y - 1 == vp[i + 1].y) {
vp.erase(vp.begin() + i);
continue;
}
if (vp[i].y == vp[i + 1].y)
if (vp[i].x + 1 == vp[i + 1].x || vp[i].x - 1 == vp[i + 1].x) {
vp.erase(vp.begin() + i);
continue;
}
i++;
}
}
void findPoint()
{
int width = src.rows;//水平
int lonth = src.cols;//垂直
int err = 0;
int q, p;
for (int i = w; i <= width - w; i++) {
for (int j = w; j <= lonth - w; j++) {
int flag = 0;
err =abs( getSrcPixel(i, j) - getSsrcPixel(w, w));
if( err > 230)
continue;
else
for (int k = i - w; k < i + w; k++) {
for (int t = j - w; t < j + w; t++) {
q = k - (i - w);
p = t - (j - w);
err = abs(getSrcPixel(k, t) - getSsrcPixel(q, p));
if (err > 230) {
flag = 1;
break;
}
}
if (flag==1)
{
break;
}
}
if (flag == 0) {
//进点集
vp.push_back(Point(j, i));
}
}
}
}
void on_mouse(int event, int x, int y, int flags, void* ustc)
{
int lonth = src.cols;
//char temp_1[20];
switch (event)
{
case EVENT_LBUTTONDOWN: {
pre_pt = Point(x, y);
} break;
case EVENT_LBUTTONUP: {
printf("%d %d ", pre_pt.x, pre_pt.y);
destroyWindow("src");
Rect rect(pre_pt.x - w, pre_pt.y - w, 2 * w, 2 * w);
ssrc = src(rect);
imshow("图像块", ssrc);
findPoint();
judge();
printf("共有%d个 ", int(vp.size()));
for (int i = 0; i < vp.size(); i++) {
printf("\n %f %f ", vp[i].x, vp[i].y);
circle(dst, vp[i],13, CV_RGB(255, 0, 0), 1, 5, 0);
char temp[20];
sprintf_s(temp, "(%d,%d)", int(vp[i].x), lonth-int(vp[i].y));
putText(dst, temp, Point(vp[i].x-2.5*w, vp[i].y+2*w), CV_FONT_HERSHEY_SCRIPT_SIMPLEX, 0.5, Scalar(255, 0, 0));
}
imshow("dst", dst);
}break;
}
}
int main()
{
namedWindow("src", WINDOW_AUTOSIZE);//WINDOW_AUTOSIZE:系统默认,显示自适应
src = imread("C:/Users/wwwww/Desktop/图像识别/123.png",1);
//1:为原图颜色,0:为灰度图,黑白颜色
src.copyTo(dst);
setMouseCallback("src", on_mouse, 0);
imshow("src", src);
waitKey(0);
return 0;
}
matlab代码
close all;
clear all;
clc;
im = imread('C:\Users\wwwww\Desktop\图像识别\123.png');
im=imresize(im,1);
figure; imshow(im);
[m,n,c]=size(im);
im = im2double(im);
%点击选取一个图像块
[c, r] = ginput(1);
c = floor(c);
r = floor(r);
%图像块宽度
w = 8;
block_im = im(r-w:r+w, c-w:c+w, :);
err = 0;
%可能匹配的位置
pnts = [];
%匹配的图像块太多
too_many_match = 0;
for i =w:m-w
for j =w:n-w
f=0;
err = sum(abs(im(i,j,:)-block_im(w, w,:))); %所选点的三个通道的取值的差
if err > 0.9
continue;
end
for k=i-w+1:i+w
for t=j-w+1:j+w
q=k-(i-w);
p=t-(j-w);
err=sum(abs(im(k,t,:)-block_im(q,p,:)));
if err> 0.9
f=1;
break;
end
end
if f==1
break;
end
end
if f~=1
pnts = [pnts; [i,j]];
end
%如果匹配的点太多,那么就要重新选择图像块
if size(pnts,1) > 50
too_many_match = 1;
break;
end
end
if 1 == too_many_match
break;
end
end
%pnts
[m,n,c]=size(im);
hold on;
len = size(pnts,1);
%删除相邻的重复点
i=1;
while(i<len)
if pnts(i,1)==pnts(i+1,1)||pnts(i,1)+1==pnts(i+1,1)||pnts(i,1)-1==pnts(i+1,1)
if pnts(i,2)+1==pnts(i+1,2)||pnts(i,2)-1==pnts(i+1,2)
pnts([i],:)=[];
end
if i==size(pnts,1)
len=size(pnts,1)
break
end
end
if pnts(i,2)==pnts(i+1,2)||pnts(i,2)+1==pnts(i+1,2)||pnts(i,2)-1==pnts(i+1,2)
if pnts(i,1)+1==pnts(i+1,1)||pnts(i,1)-1==pnts(i+1,1)
pnts([i],:)=[];
end
end
i=i+1;
len=size(pnts,1);
end
for i=1:len
plot(pnts(i,2), pnts(i,1), 'ro');
end
block_im=imresize(block_im,2);
figure;
imshow(block_im); title('图像块');
figure;
plot(pnts(:,2),pnts(:,1),'.');
set(gca,'xaxislocation','top','yaxislocation','left','ydir','reverse');
len
运行结果
最后
因为我所用的方法只是粗略比较像素值,所以误差会非常大,只是能大致识别出来这些图像,而且把允许范围的阈值设置的比较高,所以还是可以再优化的。