通过图像处理识别纸币

use*_*037 6 matlab image-processing image-recognition computer-vision image-segmentation

在纸币我想检查条带是破碎还是实线.为此我拍了一张强烈的背景照片.我得到了以下两张照片,一张是真货币,另一张是假币.我在条带存在的位置裁剪图像并进行开合重建,最后计算黑色像素.但结果并不如我所愿.有帮助吗?

这是图像:

在此输入图像描述 在此输入图像描述

%Code for the thine strip
clear all;
close all;
I = imread('IMG_4267.jpg');
imageSize = size(I);
croppedImage = imcrop(I,[300 0 30 570]);
gray=rgb2gray(croppedImage);
se1 = strel('square',2);
I1e = imerode(gray, se1);
I1e = imreconstruct(I1e, gray);
I1b = imdilate(I1e, se1);
I1c = imreconstruct(imcomplement(I1b), imcomplement(I1e));
I1d = imcomplement(I1c);
Edge2=edge(I1d,'canny');
BW1 = im2bw(Edge2);
nBlack = sum(BW1(:));
Run Code Online (Sandbox Code Playgroud)

ray*_*ica 17

这是我相当拙劣的尝试,以确定您的银行票据是假的还是真实的.我在注释之间注意到的一件事是,真正的音符使其薄带或多或少连续,而假条带在条带中具有碎片细线.可以说假钞在薄条中有多线,而真钞只有一条线.让我们尝试获取我们的图像,以便我们检测条带本身(正如您已经尝试过的那样)并计算我们看到的线条数量.如果我们只看到一条线,那就是真实的,但如果我们看到不止一条线就是假的.我将带您了解我之间的中间图像.

第1步 - 阅读图像(当然)

我将从StackOverflow直接读取您的图像. imread非常适合从在线URL中读取图像:

%%//Read in image
clear all;
close all;
Ireal = imread('http://i.stack.imgur.com/SqbnIm.jpg'); %//Real
Ifake = imread('http://i.stack.imgur.com/2U3DEm.jpg'); %//Fake
Run Code Online (Sandbox Code Playgroud)

步骤#2 - 将图像分解为HSV并进行分析

我注意到的一件事是条纹非常暗,而钞票主要是绿色.我使用了一些基本的彩色图像处理作为预处理步骤.我将图像转换为HSV(Hue-Saturation-Value)并分别查看每个组件:

%% Pre-analysis
hsvImageReal = rgb2hsv(Ireal);
hsvImageFake = rgb2hsv(Ifake);
figure;
imshow([hsvImageReal(:,:,1) hsvImageReal(:,:,2) hsvImageReal(:,:,3)]);
title('Real');
figure;
imshow([hsvImageFake(:,:,1) hsvImageFake(:,:,2) hsvImageFake(:,:,3)]);
title('Fake');
Run Code Online (Sandbox Code Playgroud)

以下是图片的样子:

在此输入图像描述

在此输入图像描述

在这段代码中,我分别为色调,饱和度和值分别显示每个组件.你会注意到一些非常特殊的东西.黑色薄条的饱和度非常高,这是有道理的,因为黑色可以被认为是纯饱和度(没有白光)的"颜色".值组件的条带值非常低,当值捕获颜色的亮度/强度时也是有意义的.

步骤#3 - 阈值饱和度和值平面以创建二进制图像

根据我上面的观察,我将对图像进行阈值处理,查看饱和度和值平面.具有相当高的组合饱和度和相当低的值的任何点都是作为黑色条带的一部分的候选者.我将自己裁剪掉条带以使事情变得更容易(正如你已经做过的那样).请注意,每张图像中条带的位置不同,因此我必须进行相应调整.我只是提取出正确的列,同时保留行和切片相同.这些饱和度和值阈值是相当临时的,所以我不得不玩这些以获得好的结果.

%%//Initial segmentation
croppedImageReal = hsvImageReal(:,90:95,:);
croppedImageFake = hsvImageFake(:,93:98,:);
satThresh = 0.4;
valThresh = 0.3;
BWImageReal = (croppedImageReal(:,:,2) > satThresh & croppedImageReal(:,:,3) < valThresh);
figure;
subplot(1,2,1);
imshow(BWImageReal);
title('Real');
BWImageFake = (croppedImageFake(:,:,2) > satThresh & croppedImageFake(:,:,3) < valThresh);
subplot(1,2,2);
imshow(BWImageFake);
title('Fake');
Run Code Online (Sandbox Code Playgroud)

这些是图像的样子:

在此输入图像描述

您可以看到真正的条带或多或少具有比假条带更多的连接性.让我们做一些处理来清理它

步骤#4 - 做一些小的关闭

如果你看一下假钞的薄黑条,你会看到每条黑线被相隔几个像素分开,而真正的音符确实没有分离.但是,您会看到在上面的真实条带中,仍然有一些部分线路断开连接.因此,让我们尝试将线连接在一起.这是安全的,因为如果我们在假图像上这样做,那么条带的各个部分相距太远,以至于关闭不应该有所作为,但它将有助于我们的真实图像分析.因此,我通过垂直的6像素线关闭这些图像.这是执行此操作的代码:

%%//Post-process
se = strel('line', 6, 90);
BWImageCloseReal = imclose(BWImageReal, se);
BWImageCloseFake = imclose(BWImageFake, se);
figure;
subplot(1,2,1);
imshow(BWImageCloseReal);
title('Real');
subplot(1,2,2);
imshow(BWImageCloseFake);
title('Fake');
Run Code Online (Sandbox Code Playgroud)

这些是图像的样子:

在此输入图像描述

第5步 - 最后清理

您会注意到,对于每个图像,边缘上都有一些噪声像素.因此,让我们使用一个通过的区域bwareaopen.此功能可删除黑白图像中小于特定区域的像素区域.我将选择15去掉沿着不属于条带的边缘的像素.因此:

%%//Area open the image
figure;
areaopenReal = bwareaopen(BWImageCloseReal, 15);
imshow(areaopenReal);
title('Real');
figure;
areaopenFake = bwareaopen(BWImageCloseFake, 15);
imshow(areaopenFake);
title('Fake');
Run Code Online (Sandbox Code Playgroud)

这是图像的样子:

在此输入图像描述

步骤#6 - 计算黑线数量

最后一步是简单计算每个图像中的黑线数量.如果只有1,则表示钞票是真实的,而如果存在多于1,则表示钞票是假的.我们可以使用bwlabel并使用第二个参数来计算有多少个对象.换一种说法:

%%//Count how many objects there are
[~,countReal] = bwlabel(areaopenReal);
[~,countFake] = bwlabel(areaopenFake);
disp(['The total number of black lines for the real note is: ' num2str(countReal)]);
disp(['The total number of black lines for the fake note is: ' num2str(countFake)]);
Run Code Online (Sandbox Code Playgroud)

我们在MATLAB中得到以下输出:

The total number of black lines for the real note is: 1
The total number of black lines for the fake note is: 4
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,真正的音符只有一行,而假音符不止一行.您必须使用此代码,具体取决于您必须使用哪个银行记录才能使其工作,但这是一个可以开始的地方.


完整代码

为了完整起见,这里是完整的代码,因此您可以自己复制和粘贴并在MATLAB中运行.

%%//Read in image
clear all;
close all;
Ireal = imread('http://i.stack.imgur.com/SqbnIm.jpg'); % Real
Ifake = imread('http://i.stack.imgur.com/2U3DEm.jpg'); % Fake

%%//Pre-analysis
hsvImageReal = rgb2hsv(Ireal);
hsvImageFake = rgb2hsv(Ifake);
figure;
imshow([hsvImageReal(:,:,1) hsvImageReal(:,:,2) hsvImageReal(:,:,3)]);
title('Real');
figure;
imshow([hsvImageFake(:,:,1) hsvImageFake(:,:,2) hsvImageFake(:,:,3)]);
title('Fake');

%%//Initial segmentation
croppedImageReal = hsvImageReal(:,90:95,:);
croppedImageFake = hsvImageFake(:,93:98,:);
satThresh = 0.4;
valThresh = 0.3;
BWImageReal = (croppedImageReal(:,:,2) > satThresh & croppedImageReal(:,:,3) < valThresh);
figure;
subplot(1,2,1);
imshow(BWImageReal);
title('Real');
BWImageFake = (croppedImageFake(:,:,2) > satThresh & croppedImageFake(:,:,3) < valThresh);
subplot(1,2,2);
imshow(BWImageFake);
title('Fake');

%%//Post-process
se = strel('line', 6, 90);
BWImageCloseReal = imclose(BWImageReal, se);
BWImageCloseFake = imclose(BWImageFake, se);
figure;
subplot(1,2,1);
imshow(BWImageCloseReal);
title('Real');
subplot(1,2,2);
imshow(BWImageCloseFake);
title('Fake');

%%//Area open the image
figure;
areaopenReal = bwareaopen(BWImageCloseReal, 15);
subplot(1,2,1);
imshow(areaopenReal);
title('Real');
subplot(1,2,2);
areaopenFake = bwareaopen(BWImageCloseFake, 15);
imshow(areaopenFake);
title('Fake');

%%//Count how many objects there are
[~,countReal] = bwlabel(areaopenReal);
[~,countFake] = bwlabel(areaopenFake);
disp(['The total number of black lines for the real note is: ' num2str(countReal)]);
disp(['The total number of black lines for the fake note is: ' num2str(countFake)]);
Run Code Online (Sandbox Code Playgroud)

编辑 - 2014年9月4日

您联系了我,想知道如何检测每个音符右侧的大黑条.这实际上并不是那么糟糕.您发布的另一张假钞的图片尺寸与其他图片不同.因此,我将调整此图像的大小,以使此图像与您显示的其他图像大致相同.这是您在评论中发布的图片:

通过查看所有音符,它们悬停在第195列到第215列之间.这假设每个图像有320列.现在,我如何检测钞票是否是假货的过程是通过查看黑条本身的整体强度.你会注意到假钞上没有黑色条带,或条带相当暗淡和褪色.我们当然可以利用这个优势.这是我用来检测黑条的快速列表:

  • 读入图像并在必要时将它们调整为所有相同的列
  • 为所有图像提取第195列到第215列
  • 使用将图像转换为灰度 rgb2gray
  • 使用大约30级强度对图像进行阈值处理.我使用了30个启发式算法,因为这主要是我看到黑色条带组成的强度.然后反转图像,使黑色变为白色.我需要将黑色条带变成白色以供进一步分析.我习惯im2bw这样做.
  • 我像以前一样打开图像区域,但是指定一个大约100的区域,以确保我摆脱任何虚假的噪声和孤立的像素.
  • 我使用5 x 5的方形结构元素进行闭合,以确保靠近较大区域的任何断开区域彼此连接.
  • 然后我计算剩下的对象总数.如果计数不等于1,那么这是假注.如果它只是1,那么这是一个真实的笔记.

这是完整的代码:

%% //Read in images
clear all;
close all;
Ireal = imread('http://i.stack.imgur.com/SqbnIm.jpg'); % Real
Ifake = imread('http://i.stack.imgur.com/2U3DEm.jpg'); % Fake
Ifake2 = imread('http://i.imgur.com/SVJrwaV.jpg'); % Fake #2
% //Resize so that we have the same dimensions as the other images
Ifake2 = imresize(Ifake2, [160 320], 'bilinear');

%% //Extract the black strips for each image
blackStripReal = Ireal(:,195:215,:);
blackStripFake = Ifake(:,195:215,:);
blackStripFake2 = Ifake2(:,195:215,:);

figure(1);
subplot(1,3,1);
imshow(blackStripReal);
title('Real');
subplot(1,3,2);
imshow(blackStripFake);
title('Fake');
subplot(1,3,3);
imshow(blackStripFake2);
title('Fake #2');

%% //Convert into grayscale then threshold
blackStripReal = rgb2gray(blackStripReal);
blackStripFake = rgb2gray(blackStripFake);
blackStripFake2 = rgb2gray(blackStripFake2);

figure(2);
subplot(1,3,1);
imshow(blackStripReal);
title('Real');
subplot(1,3,2);
imshow(blackStripFake);
title('Fake');
subplot(1,3,3);
imshow(blackStripFake2);
title('Fake #2');

%% //Threshold using about intensity 30
blackStripRealBW = ~im2bw(blackStripReal, 30/255);
blackStripFakeBW = ~im2bw(blackStripFake, 30/255);
blackStripFake2BW = ~im2bw(blackStripFake2, 30/255);

figure(3);
subplot(1,3,1);
imshow(blackStripRealBW);
title('Real');
subplot(1,3,2);
imshow(blackStripFakeBW);
title('Fake');
subplot(1,3,3);
imshow(blackStripFake2BW);
title('Fake #2');

%% //Area open the image
figure(4);
areaopenReal = bwareaopen(blackStripRealBW, 100);
subplot(1,3,1);
imshow(areaopenReal);
title('Real');
subplot(1,3,2);
areaopenFake = bwareaopen(blackStripFakeBW, 100);
imshow(areaopenFake);
title('Fake');
subplot(1,3,3);
areaopenFake2 = bwareaopen(blackStripFake2BW, 100);
imshow(areaopenFake2);
title('Fake #2');

%% //Post-process
se = strel('square', 5);
BWImageCloseReal = imclose(areaopenReal, se);
BWImageCloseFake = imclose(areaopenFake, se);
BWImageCloseFake2 = imclose(areaopenFake2, se);
figure(5);
subplot(1,3,1);
imshow(BWImageCloseReal);
title('Real');
subplot(1,3,2);
imshow(BWImageCloseFake);
title('Fake');
subplot(1,3,3);
imshow(BWImageCloseFake2);
title('Fake #2');

%% //Count the total number of objects in this strip
[~,countReal] = bwlabel(BWImageCloseReal);
[~,countFake] = bwlabel(BWImageCloseFake);
[~,countFake2] = bwlabel(BWImageCloseFake2);
disp(['The total number of black lines for the real note is: ' num2str(countReal)]);
disp(['The total number of black lines for the fake note is: ' num2str(countFake)]);
disp(['The total number of black lines for the second fake note is: ' num2str(countFake2)]);
Run Code Online (Sandbox Code Playgroud)

请记住,您必须使用这些参数来满足您的目的.以下是每个步骤的数字:

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

......最后是对象计数:

The total number of black lines for the real note is: 1
The total number of black lines for the fake note is: 2
The total number of black lines for the second fake note is: 0
Run Code Online (Sandbox Code Playgroud)

祝好运!

  • @rayryeng +1为了努力,哇!大力的工作! (6认同)