MATLAB——基於圖像相減的紙牌識別系統

一、設計要求

這是數字圖像處理課程作業的其中一道題目,設計要求如下。
紙牌識別系統的設計要求
所用的數據集是我舍友在網上下載的,個人覺得很高清,也懶得去拍照,就直接白嫖了,自己做測試的話,可以自行取材,注意拍攝的大小合適、位置恰當、光照均勻;如果出現光照不均,識別結果可能會偏離更多,需要提前消除光照不均的影響。
在這裏插入圖片描述


二、編程思路

Created with Raphaël 2.2.0 源數據集 獲取模板 輸入測試圖像 將模板分別於測試圖像相減,取絕對值 確定與輸入圖像差值最小的模板 輸出識別結果 識別完成

我的文件管理如下:
在這裏插入圖片描述

1、獲取模板(含代碼)

運行該程序之後,將獲得差不多大小(大小會有幾個像素的差別)的模板,存放在同根目錄下的mask文件夾下,將所需要的數字和類型包含在待識別範圍內,減小識別量。

%-------------GetImagesMask.m------------------------
clear;clc;
%用於獲取模板
num = ['2' '3' '4' '5' '6' '7' '8' '9' '10'];
alpha = ['B' 'F' 'M' 'R'];
N = 1;
Al = 3;
for i=1:4
    path=strcat('../images/',alpha(i),'_',num(N),'.JPG');
    name = strcat(alpha(i),'_',num(N));
    A = imread(path);
    [x,y,z] = size(A);
    Shape_Left_Top = A(x/6 : 7*x/24, y/25 : y/7, 1 : z);
    % 圖像二值化,反色
    Shape_Left_Top_BW = ~im2bw(rgb2gray(Shape_Left_Top),0.5);
    % 中值濾波去除椒鹽噪聲,[3,3]爲窗口大小,不同噪聲用不同的濾波器
    mask_A = medfilt2(Shape_Left_Top_BW,[3,3]);
    restore_path_A = strcat('../mask/',alpha(i),'.JPG');
    imwrite(mask_A,restore_path_A); %將模板存放在mask文件夾中
end
for i = 1:9
    if i==9
        path=strcat('../images/',alpha(Al),'_',num(i),num(i+1),'.JPG');
        name = strcat(alpha(Al),'_',num(i),num(i+1));
    else
        path=strcat('../images/',alpha(Al),'_',num(i),'.JPG');
        name = strcat(alpha(Al),'_',num(i));
    end
    A = imread(path);
    [x,y,z] = size(A);
    Number_Left_Top = A(x/25 : x/6, y/30: y/7, 1 : z);  %自己確定的大小,可更改
     % 圖像二值化,反色
    Number_Left_Top_BW = ~im2bw(rgb2gray(Number_Left_Top),0.5);
    % 中值濾波去除椒鹽噪聲,[3,3]爲窗口大小
    mask_N = medfilt2(Number_Left_Top_BW,[3,3]);
    if i==9
        restore_path_N = strcat('../mask/',num(i),num(i+1),'.JPG');
    else
        restore_path_N = strcat('../mask/',num(i),'.JPG');
    end
    imwrite(mask_N,restore_path_N);
end

獲得的模板如下:
在這裏插入圖片描述

2、輸入圖像測試(含代碼)

需要注意的是,將輸入圖像剪裁後的大小不一定與模板大小一致,所以要做預處理,選擇模板與截取的輸入圖像中較小的一方的大小,然後截取另外一方爲合適的大小。

%------------------PuKeRecog.m---------------------
clear;clc;
%輸入圖像
A = imread('../images/M_6.JPG');
[x,y,z] = size(A);
% 截取圖像
Number_Left_Top = A(x/25 : x/6, y/30: y/7, 1 : z);
Shape_Left_Top =A(x/6 : 7*x/24, y/25 : y/7, 1 : z);
figure;
imshow(A)
% figure(1)
% imshow(Number_Left_Top)
% figure(2)
% imshow(Shape_Left_Top)
% 圖像二值化,反色
Shape_Left_Top_BW = ~im2bw(rgb2gray(Shape_Left_Top),0.5);
Number_Left_Top_BW = ~im2bw(rgb2gray(Number_Left_Top),0.5);
% 中值濾波去除椒鹽噪聲,[3,3]爲窗口大小
Shape_Left_Top_BW = medfilt2(Shape_Left_Top_BW,[3,3]);
Number_Left_Top_BW = medfilt2(Number_Left_Top_BW,[3,3]);
%模板參數
num = ['2' '3' '4' '5' '6' '7' '8' '9' '10'];
alpha = ['B' 'F' 'M' 'R'];
%分別與模板類型圖像做減操作
diff_A = [0 0 0 0]; %用於存儲與四個類型模板相減的差值
for i=1:4
    path=strcat('../mask/',alpha(i),'.JPG');
    mask_A = imread(path);
    mask_A =~ mask_A;
    mask_A =~ mask_A;
    [h_m,w_m] = size(mask_A);
    [h_a,w_a] = size(Shape_Left_Top_BW);
    if h_m<h_a
        H=h_m;
    else
        H=h_a;
    end
    if w_m<w_a
        W=w_m;
    else
        W=w_a;
    end
    DD=zeros(H,W);
    mask_A=double(mask_A);
    for j=1:H
        for k=1:W
            DD(j,k) = Shape_Left_Top_BW(j,k) - mask_A(j,k);
        end
    end
    diff_A(i) = sum(sum(abs(DD)));
end
[minVal_a minInd_a] = min(diff_A);
switch minInd_a
    case 1
        name=strcat('the kind is:',alpha(1));
        disp(name)
    case 2
         name=strcat('the kind is:',alpha(2));
        disp(name)
    case 3
         name=strcat('the kind is:',alpha(3));
        disp(name)
    case 4
         name=strcat('the kind is:',alpha(4));
        disp(name)
    otherwise
        disp('No found!')
end

%與模板數字圖像做減操作
diff_N = [0 0 0 0 0 0 0 0 0]; %用於存儲與九個數字模板相減的差值
for i=1:9
    if i==9
        path=strcat('../mask/',num(i),num(i+1),'.JPG');
    else
        path=strcat('../mask/',num(i),'.JPG');
    end
    mask_N = imread(path);
    mask_N =~ mask_N;
    mask_N =~ mask_N;
    [h_m,w_m] = size(mask_N);
    [h_a,w_a] = size(Number_Left_Top_BW);
    if h_m<h_a
        H=h_m;
    else
        H=h_a;
    end
    if w_m<w_a
        W=w_m;
    else
        W=w_a;
    end
    DD=zeros(H,W);
    mask_N=double(mask_N);
    for j=1:H
        for k=1:W
            DD(j,k) = Number_Left_Top_BW(j,k) - mask_N(j,k);
        end
    end
    diff_N(i) = sum(sum(abs(DD)));
end
[minVal_n minInd_n] = min(diff_N);
switch minInd_n
    case 1
        name=strcat('the number is:',num(1));
        disp(name)
    case 2
         name=strcat('the number is: ',num(2));
        disp(name)
    case 3
         name=strcat('the number is :',num(3));
        disp(name)
    case 4
         name=strcat('the number is :',num(4));
        disp(name)
    case 5
         name=strcat('the number is :',num(5));
        disp(name)
    case 6
         name=strcat('the number is :',num(6));
        disp(name)
    case 7
         name=strcat('the number is :',num(7));
        disp(name)
    case 8
         name=strcat('the number is :',num(8));
        disp(name)
    case 9
         name=strcat('the number is :',num(9),num(10));
        disp(name)
    otherwise
        disp('No found!')
end

三、測試結果

測試1
輸入爲:
在這裏插入圖片描述
輸出爲:
在這裏插入圖片描述
測試2
輸入爲:
在這裏插入圖片描述
輸出爲:
在這裏插入圖片描述
測試3
輸入爲:
在這裏插入圖片描述
輸出爲:
在這裏插入圖片描述
測試4
輸入爲:
在這裏插入圖片描述
輸出爲:
在這裏插入圖片描述


















四、性能分析

這種相減作差的識別方法優點是模板的形狀一致,但對所拍攝圖片的位置有很嚴格的要求,若是模板選擇正確,拍攝紙牌的位置與模板一致,準確率是可以很高的,比手寫數字識別還要高很多(手寫數字的形狀也不唯一,因此準確率很低。)但如果位置一旦出現偏差,那麼識別錯誤的概率就會大大提高。
如下,類型識別錯誤,數字識別正確:
在這裏插入圖片描述
在這裏插入圖片描述


五、另外一道編程題(沒錯,就是手寫數字識別)

1、圖像相減方法

利用同樣的圖像相減方法,那識別正確率是相當的低呀!(雖然早就預料到了:),這次用的是Python,裏面有些代碼是借鑑網上大佬的,我很想找出處標明,但我發現我找不到了,害。

Step1:採集手寫數字圖像數據

在這裏插入圖片描述

Step2:運行MNIST_Pre.py程序對數據進行處理,變成二值化圖像

在這裏插入圖片描述

Step3:運行MNIST_Pro.py程序,將輸入圖片分別與各個模板圖片進行減操作,計算剩餘有灰度值的像素點數,選取最小值,進而對手寫數字進行識別,輸出結果

在這裏插入圖片描述

Step4:測試

在這裏插入圖片描述
在這裏插入圖片描述

Step5:性能分析

通過模板相減的辦法進行識別,對模板要求很高,模板的位置、形狀等不同,對同一圖片的識別效果也會不同。加上手寫數字的變化性很大,很難尋找到統一不變的特徵。該模型識別率很低。

程序代碼

#-------------------------------------MNIST_Pre.py----------------------------------------------
import cv2
global img
global point1,point2
def on_mouse(event,x,y,flags,param):
    global img,point1,point2
    img2 = img.copy()
    if event == cv2.EVENT_LBUTTONDOWN:
        point1 = (x,y)
        cv2.circle(img2,point1,10,(0,255,0),5)
        cv2.imshow('image',img2)
    elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON): #按住左鍵拖拽
        cv2.rectangle(img2,point1,(x,y),(255,0,0),5) #圖像,矩形頂點,相對頂點,顏色,粗細
        cv2.imshow('image',img2)
    elif event == cv2.EVENT_LBUTTONUP: #左鍵釋放
        point2 = (x,y)
        cv2.rectangle(img2,point1,point2,(0,0,255),5)
        cv2.imshow('image',img2)
        min_x = min(point1[0],point2[0])
        min_y = min(point1[1],point2[1])
        width = abs(point1[0]-point2[0])
        height = abs(point1[1]-point2[1])
        cut_img = img[min_y:min_y + height,min_x:min_x + width]
        resize_img = cv2.resize(cut_img,(28,28)) #調整圖像尺寸爲28*28
        ret,thresh_img = cv2.threshold(resize_img,127,255,cv2.THRESH_BINARY) #二值化
        cv2.imshow('result',thresh_img)
        cv2.imwrite('Images/05.png',thresh_img)  #存放位置

def main():
    global img
    img = cv2.imread(r'C:\\Users\\LENOVO\\Desktop\\test.jpg')
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    cv2.namedWindow('image')
    cv2.setMouseCallback('image',on_mouse)
    cv2.imshow('image',img)
    cv2.waitKey(0)

if __name__ == '__main__':
    main()

#----------------------------------------MNIST_Pro.py---------------------------------------
import cv2
import numpy as np
# # 像素取反
# def get_img_reserve(img):
# #直接調用反選函數
#     dst = cv2.bitwise_not(img)
#     cv2.imshow("reserve",dst)
#     cv2.imshow('src',img)
#     return dst
#
# img = cv2.imread('Images/0.png')
# dst = get_img_reserve(img)
# kernel = np.ones((3,3),np.uint8)
# erosion = cv2.erode(dst,kernel,iterations = 1)
# cv2.imwrite('Images/pre_0.png',erosion)
# cv2.imshow('erode',erosion)
# cv2.waitKey()

def findSmallest(arr):
    smallest = arr[0]
    smallest_index = 0
    for i in range(1,len(arr)):
        if arr[i] < smallest:
            smallest = arr[i]
            smallest_index = i
    return smallest_index

counts = np.arange(10)
#print(counts)
for t in range(10):
    #print('-------------------{} processing-------------------'.format(t))  #模板圖片
    path = 'Images/1'+str(t)+'.png'
    mask = cv2.imread(path)
    img = cv2.imread('Images/6.png')  #輸入測試圖片
    differ = img - mask
    # print(differ)
    # (h,w,d)=differ.shape
    # for i in range(w):
    #     for j in range(h):
    #         for k in range(d):
    #             print(differ[i][j][k])
    differ = abs(differ)
    differ_gray = cv2.cvtColor(differ,cv2.COLOR_BGR2GRAY)
    # (h,w)=differ_gray.shape
    # for i in range(w):
    #     for j in range(h):
    #             print(differ[i][j])
    ret,thresh = cv2.threshold(differ_gray,0,255,cv2.THRESH_BINARY)
    cv2.imwrite('Images/differ'+str(t)+'.png',thresh)
    #cv2.imshow('differ',thresh)
    (h, w) = thresh.shape
    #print("width={}, height={}".format(w, h))
    count = 0
    for i in range(w):
        for j in range(h):
            if thresh[i][j] == 255:
                count = count + 1
    counts[t] = count
    #print('count'+str(t)+'= ',count)

min = findSmallest(counts)
print('the number is ',min)
cv2.imshow('Writing Number',img)
cv2.waitKey()

2、基於TensorFlow的手寫數字識別系統

之前學習TensorFlow的時候,跟着大佬打過的代碼,還是深度學習香,準確率也高,po這裏,一起學習。

(1)步驟

Step1:載入TensorFlow裏的mnist數據;
Step2:訓練網絡,利用梯度下降算法訓練模型,利用AdamOptimizer優化器提高精確度;
Step3:載入自己的圖像測試。

(2)測試

輸入圖像:
在這裏插入圖片描述
處理之後的圖像:
在這裏插入圖片描述
測試結果:
在這裏插入圖片描述




(3)模型性能

在這裏插入圖片描述

(4)程序代碼

#我的TensorFlow版本是2,爲了使用某些功能,將其表現爲版本1,用的編輯器是jupyter
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
from tensorflow.examples.tutorials.mnist import input_data
#載入數據集
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)

#每個數據集大小
batch_size = 30
#計算一共有多少個數據集
n_batch = mnist.train.num_examples // batch_size

#定義兩個placeholder
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])

#定義神經網絡中間層
Weights_L1 = tf.Variable(tf.zeros([784,30]))
biases_L1 = tf.Variable(tf.zeros([30]))
Wx_plus_b_L1 = tf.matmul(x,Weights_L1) + biases_L1
L1 = tf.nn.tanh(Wx_plus_b_L1)

#創建一個簡單的神經網絡
W = tf.Variable(tf.random_normal([30,10]))
b = tf.Variable(tf.zeros([10]))
prediction = tf.nn.softmax(tf.matmul(L1,W)+b)

#二次代價函數
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))
#使用梯度下降法
#train_step = tf.train.GradientDescentOptimizer(0.3).minimize(loss)
train_step = tf.train.AdamOptimizer(1e-3).minimize(loss)

#初始化變量
init = tf.global_variables_initializer()

#結果存放在一個布爾型列表中
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1)) #argmax返回一維張量中最大的值所在的位置
#求準確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

with tf.Session() as sess:
    sess.run(init)
    for epoch in range(21):
        for batch in range(n_batch):
            batch_xs,batch_ys = mnist.train.next_batch(batch_size)
            sess.run(train_step,feed_dict={
   
   x:batch_xs,y:batch_ys})
            
        acc = sess.run(accuracy,feed_dict={
   
   x:mnist.test.images,y:mnist.test.labels})
        print('Iter' + str(epoch) + ",Testing Accuracy" + str(acc))

#圖像預處理
import cv2
global img
global point1,point2
def on_mouse(event,x,y,flags,param):
    global img,point1,point2
    img2 = img.copy()
    if event == cv2.EVENT_LBUTTONDOWN:
        point1 = (x,y)
        cv2.circle(img2,point1,10,(0,255,0),5)
        cv2.imshow('image',img2)
    elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON): #按住左鍵拖拽
        cv2.rectangle(img2,point1,(x,y),(255,0,0),5) #圖像,矩形頂點,相對頂點,顏色,粗細
        cv2.imshow('image',img2)
    elif event == cv2.EVENT_LBUTTONUP: #左鍵釋放
        point2 = (x,y)
        cv2.rectangle(img2,point1,point2,(0,0,255),5)
        cv2.imshow('image',img2)
        min_x = min(point1[0],point2[0])
        min_y = min(point1[1],point2[1])
        width = abs(point1[0]-point2[0])
        height = abs(point1[1]-point2[1])
        cut_img = img[min_y:min_y + height,min_x:min_x + width]
        resize_img = cv2.resize(cut_img,(28,28)) #調整圖像尺寸爲28*28
        ret,thresh_img = cv2.threshold(resize_img,127,255,cv2.THRESH_BINARY) #二值化
        cv2.imshow('result',thresh_img)
        cv2.imwrite('images/test.png',thresh_img)  #存放位置

def main():
    global img
    img = cv2.imread(r'C:\Users\LENOVO\Desktop\test.jpg')
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    cv2.namedWindow('image')
    cv2.setMouseCallback('image',on_mouse)
    cv2.imshow('image',img)
    cv2.waitKey(0)

if __name__ == '__main__':
main()

#利用訓練好的模型進行測試
from PIL import Image
import tensorflow as tf
import numpy as np

im = Image.open('images/test.png')
data = list(im.getdata())
result = [(255-x)*1.0/255.0 for x in data] 
print(result)

# 爲輸入圖像和目標輸出類別創建節點
x = tf.placeholder("float", shape=[None, 784]) # 訓練所需數據  佔位符

# *************** 構建多層卷積網絡 *************** #
def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1) # 取隨機值,符合均值爲0,標準差stddev爲0.1
  return tf.Variable(initial)

def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)

def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

x_image = tf.reshape(x, [-1,28,28,1]) # -1表示任意數量的樣本數,大小爲28x28,深度爲1的張量

W_conv1 = weight_variable([5, 5, 1, 32]) # 卷積在每個5x5的patch中算出32個特徵。
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) 
h_pool1 = max_pool_2x2(h_conv1)

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

# 在輸出層之前加入dropout以減少過擬合
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

# 全連接層
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

# 輸出層
# tf.nn.softmax()將神經網絡的輸層變成一個概率分佈
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

saver = tf.train.Saver() # 定義saver

# *************** 開始識別 *************** #
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver.restore(sess, "save/model.ckpt")#這裏使用了之前保存的模型參數

    prediction = tf.argmax(y_conv,1)
    predint = prediction.eval(feed_dict={
   
   x: [result],keep_prob: 1.0}, session=sess)

    print("recognize result: %d" %predint[0])

555數圖作業讓我沒有頭髮
如需轉載,請標明出處,xixixi。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章