如何在图片中识别特定图像并找出(c语言和matlab)

前言

导师给了一个任务,主要是在一张图片中识别出特定的图像,并标记出相应物体的位置(在坐标图上呈现),分别用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


运行结果

原图在这里插入图片描述
在这里插入图片描述

最后

因为我所用的方法只是粗略比较像素值,所以误差会非常大,只是能大致识别出来这些图像,而且把允许范围的阈值设置的比较高,所以还是可以再优化的。

  • 3
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个使用OpenCV库进行数字识别C语言代码示例: ```c #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取图像 Mat img = imread("digits.png"); // 将图像转换为灰度图 Mat gray; cvtColor(img, gray, COLOR_BGR2GRAY); // 将图像分割成小块 vector<Mat> digits; int rows = gray.rows / 50; int cols = gray.cols / 100; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { Rect roi(j * 100, i * 50, 100, 50); Mat digit = gray(roi); digits.push_back(digit); } } // 训练数字分类器 Ptr<ml::KNearest> knn = ml::KNearest::create(); Mat trainData; Mat labels; for (int i = 0; i < digits.size(); i++) { Mat sample; resize(digits[i], sample, Size(10, 10)); sample = sample.reshape(1, 1); trainData.push_back(sample); labels.push_back(i / 5); } knn->train(trainData, ml::ROW_SAMPLE, labels); // 识别数字 for (int i = 0; i < digits.size(); i++) { Mat sample; resize(digits[i], sample, Size(10, 10)); sample = sample.reshape(1, 1); int response = knn->predict(sample); cout << response << " "; if ((i + 1) % cols == 0) cout << endl; } return 0; } ``` 这个示例程序将一个数字图片分割成小块,每个小块都是一个数字。然后将每个数字样本转换为10x10像素的图像,并使用KNN分类器进行训练和识别。最后输出每个小块对应的数字。在这个示例程序,数字图片应该命名为“digits.png”并与源代码文件放在同一目录下。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值