前言
导师给了一个任务,主要是在一张图片中识别出特定的图像,并标记出相应物体的位置(在坐标图上呈现),分别用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 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
;
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
);
src
= imread("C:/Users/wwwww/Desktop/图像识别/123.png",1);
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
运行结果
最后
因为我所用的方法只是粗略比较像素值,所以误差会非常大,只是能大致识别出来这些图像,而且把允许范围的阈值设置的比较高,所以还是可以再优化的。