这是我在确定您的钞票是假钞还是真钞时相当拙劣的尝试。我注意到纸币之间的一件事是,真纸币的细条或多或少是连续的,而假纸条的细线是零散的。可以说,假钞票在细条上多行,而真钞只有一行。让我们尝试获取我们的图像,以便我们检测条带本身(正如您也尝试过的那样)并计算我们看到的行数。如果我们只看到一条线,那是真的,但如果我们看到多条线,那就是假的。我将向您介绍我是如何处理中间图像的。
第 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
第 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');
图片如下:
在这段代码中,我将每个组件并排显示,分别表示色调、饱和度和值。你会注意到一些非常奇怪的东西。黑色细条具有相当高的饱和度,这是有道理的,因为黑色可以被视为纯饱和度(没有白光)的“颜色”。 value 组件的条带的值非常低,这也是有意义的,因为 value 捕获了颜色的亮度/强度。
第 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');
这些是图像的样子:
您可以看到,真正的条带或多或少比假条带具有更多的连通性。让我们做更多的处理来清理它
步骤 #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');
这些是图像的样子:
第 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');
图片如下所示:
第 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)]);
我们在 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
如您所见,真钞只有一行,而假钞不止一行。您必须使用此代码,具体取决于您必须使用哪种钞票才能使其工作,但这是开始的地方。
完整代码
为了完整起见,这里是完整的代码,您可以自己复制粘贴并在 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)]);
编辑 - 2014 年 9 月 4 日
您联系了我,想知道如何检测每个音符右侧的黑色大条。这实际上并没有那么糟糕。您发布的另一张假钞的图片与其他图片的尺寸不同。因此,我将调整此图像的大小,以使此图像与您显示的其他图像的大小大致相同。这是您在 cmets 中发布的图片:
通过查看所有注释,它们会在第 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)]);
请记住,您必须使用这些参数来满足您的目的。以下是每个步骤中的数字:
...最后是对象计数:
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
祝你好运!