數字圖像處理、數學形態學、MATLAB GUI實現簡單找茬軟件

0、簡介

  這個小做品是個人數字圖像處理課程設計,應用基本的圖像處理知識與MATLAB的基本腳本編程,實現一個簡單的找茬軟件。軟件實現過程當中使用到的找茬遊戲圖片來源有「夢幻找茬」、「圖圖找茬」。若有興趣的人能夠親自玩下這兩個遊戲。本程序主要目的是練習數字圖像處理的基本知識、數學形態學以及MATLAB語言。因爲時間與能力的有限,並無作的很好,各位大神小踩,謝謝。html

一、所需知識

  matlab基本語言;算法

  matlab GUI實現;編程

  數字圖像處理基本知識;dom

  數學形態學基本知識;函數

 二、算法函數實現過程

  

 

  1)圖像獲取分割tornado

    本來的課程設計要求就是要求使用的是遊戲界面截圖,使用的圖片就是存在兩邊的圖,兩邊的圖是存在差別區域的,首先要作的就是將圖像簡單進行豎直平分分割。工具

   

 

  2)計算圖像偏移裁剪測試

    因爲通常的截圖左右兩邊的圖並不能保證對稱,因此咱們須要計算利用圖片的25%中心區域來計算左右兩邊圖的偏移量,再使用這偏移量來裁剪使得兩邊的圖片儘量重合。這樣查找差別區域的時候就不會出現額外因偏移出現的錯誤標定。因爲我測試的圖像使用的是800*500的圖,逐個像素點計算,共須要比較的像素點個數大概是800*500*0.25*20=2000 000次,因此通常的電腦都須要3分鐘。ui

 

  3)三通道不相同區域提取spa

    本來課程設計的要求是用彩色轉灰度後再提取出不一樣的區域,可是轉換獲得的灰度的茬的差別有些存在的不明顯,因此最後我選擇使用紅藍綠三通道來分離出茬的區域。利用原有的顏色差別來分離出茬的區域成效明顯好於灰度圖像提取。我這裏是直接使用MATLAB內置有的imabsdiff()函數來直接獲取各個通道不一樣的區域。而後將各個通道不一樣的區域相加起來,再使用imopen(),imclose()函數進行開閉運算。實際的圖像看起來是一致的顏色,其實存在有必定的差值,甚至是較大的毛刺,因此必須是使用開閉運算來消除毛刺與噪聲。

 

  4)矩形框標定顯示

    爲了更明顯的顯示出茬的位置,最後使用一個矩形標定的函數來繪製出茬的區域。首先是使用MATLAB自帶的工具函數bwlabel()獲取茬區域的連通區域,得到到數據有標定標定好的連通區域與連通區域個數。 再用regionprops()獲取連通區域信息,獲得的信息有面積"area"、矩形框位置"boundingbox"、連通區域中心"central"。獲得這些數據,就能夠很好的使用矩形框定函數框定茬的位置。

 

  5)MATLAB GUI實現

    MATLAB的GUI仍是比較簡單的,初學者須要注意的就只有

      a.初始化函數

      b.使用句柄傳參、或者設置全局變量傳參

      c.按鍵響應事件,實際就是調用的函數

     MATLAB的全部顯示均可以是控件顯示的,如 :set(handles.radiobutton1,'visible','off');  就是設置單選框的隱藏不顯示,涉及到的參數鍵與值均可以在GUI繪製的界面的屬性中找到。最後一件事情就是MATLAB的GUI實現以後能夠打包成可執行文件,可是須要使用的電腦須要安裝編譯電腦上的MCRInstaller.exe程序。因此MATLAB的GUI程序幾乎是不可能脫離MATLAB運行,由於GUI打包幾乎都涉及到MATLAB內置的畫圖函數,因此目的主機必需要擁有MATLAB整個運行庫才能夠運行GUI。

三、找茬算法源碼

主文件:

clear
close all;
%%讀取圖片,並顯示
fileName = 'test14.png';
img = imread(fileName);
% figure();imshow(img);title('原圖');

%獲取圖片信息  
[image_h,image_w,image_c] = size(img);

image_w2 = ceil(image_w/2);

%獲取灰度圖像
img_gray = rgb2gray(img);





%%對源圖片對半豎直分割
img_M1 = zeros(image_h,image_w2,3);
img_M2 = zeros(image_h,image_w2,3);

img_M1 = imcrop(img,[0,0,image_w2,image_h]);
img_M1 = uint8(img_M1);
img_M1_gray = rgb2gray(img_M1);
figure(); imshow(img_M1);title('原左圖');

img_M2 = imcrop(img,[image_w2+1,0,image_w2,image_h]);
img_M2 = uint8(img_M2);
img_M2_gray = rgb2gray(img_M2);
 figure(); imshow(img_M2);title('原右圖');


%%判斷是否須要一鍵找茬
% yijian_flag = 0;
% char = input('是否一鍵找茬,y/n:','s');
% if char=='y'
%     yijian_flag = 1;
% end
% num_fine = 0;
% %輸入偏移量
% if yijian_flag == 0
%     while(~num_fine)
%         pic = input('請肯定要偏移的圖,l/r:','s');
%         pic_dx = input('請輸入豎直偏移量(0~8):');
%         pic_dy = input('請輸入豎直偏移量(0~8):');
%         
%         if( ((pic=='l')| (pic=='r'))&(pic_dx>=0)& (pic_dx<=8)&(pic_dy>=0)& (pic_dy<=8) )
%             num_fine = 1;
%         else
%              fprintf('輸入錯誤,請從新輸入!!!\n');
%         end
%     end
% else
%     pic = 'l';
%     pic_dx = 0;
%     pic_dy = 0;
% end


%針對test01.jpg默認值
pic = 'l';
pic_dx = 0;
pic_dy = 0;

%%進行圖片偏移
img_M1_O = zeros(image_h+pic_dx,image_w2+pic_dy,3);
img_M2_O = zeros(image_h+pic_dx,image_w2+pic_dy,3); 
img_M1_O = uint8(img_M1_O);
img_M2_O = uint8(img_M2_O);
img_M1_O(:,:,:) = 255;
img_M2_O(:,:,:) = 255;

    
    
if pic==1
    for i = 1:image_h
        for  j = 1:image_w2
            img_M1_O(i+pic_dx,j+pic_dy,:) = img_M1(i,j,:);
        end
    end
    
    for i = 1:image_h
        for  j = 1:image_w2
            img_M2_O(i,j,:) = img_M2(i,j,:);
        end
    end
    
else
    for i = 1:image_h
       for  j = 1:image_w2
            img_M2_O(i+pic_dx,j+pic_dy,:) = img_M2(i,j,:);
        end
    end
    
    for i = 1:image_h
        for  j = 1:image_w2
            img_M1_O(i,j,:) = img_M1(i,j,:);
        end
    end
    
end
figure();imshow(img_M1_O);title('左圖偏移後');
figure();imshow(img_M2_O);title('右圖偏移後');


%%計算出左右圖片誤差值
img_M1_gray = rgb2gray(img_M1_O);
img_M2_gray = rgb2gray(img_M2_O);

% 根據圖片中心鎖定圖片中心
image_h41 = ceil(image_h/4);
image_w41 = ceil(image_w2/4);

image_h43 = image_h41*3;
image_w43 = image_w41*3;

differ = 255*200*200;
differ = uint32(differ);
dx_min = 0;
dy_min = 0;

tmp = 0;
count = 0;
count = uint32(count);
qiuhe = zeros(600);
qiuhe = uint32(qiuhe);
z = 1;
for dx=-(10+pic_dx):10+pic_dx
    for dy=-(10+pic_dy):10+pic_dy
        
        for i=image_h41:image_h43
            for j=image_w41:image_w43
                tmp = uint32(abs(img_M1_gray(i,j)-img_M2_gray(i+dx,j+dy)));
                count = count + tmp;
            end
        end
        qiuhe(z) = count;
        z = z+1;
                
        if count<differ
            differ = count
            dx_min = dx
            dy_min = dy
        end
        count = 0; %count計數清零       
    end
end

% %針對test01.jpg默認值
% dx_min = 0
% dy_min = 1


%%根據偏移量裁剪左右圖
image_Nh = image_h-abs(dx_min);
image_Nw = image_w2-abs(dy_min);
img_N1 = zeros(image_Nh,image_Nw);
img_N2 = img_N1;

%判斷裁剪所需值
if dx_min<=0
    dx1 = -dx_min;
    dx2 = 0;
else
    dx2 = dx_min;
    dx1 = 0;
end

if dy_min<=0
    dy1 = -dy_min;
    dy2 = 0;
else
    dy2 = dy_min;
    dy1 = 0;
end


img_N1 = zeros(image_Nh,image_Nw,3);
img_N2 = img_N1;
for i=1:image_Nh
    for j=1:image_Nw
            img_N1(i,j,:) = img_M1_O(i+dx1,j+dy1,:);
    end
end
img_N1 = uint8(img_N1);
figure(); imshow(img_N1);title('裁剪好後的左圖');



for i=1:image_Nh
    for j=1:image_Nw
        img_N2(i,j,:) = img_M2_O(i+dx2,j+dy2,:);
    end
end
img_N2 = uint8(img_N2);
figure(); imshow(img_N2);title('裁剪好後的右圖');


%%經過三個通道分別找茬後再綜合
img_N2_R = img_N2(:,:,1);
img_N2_G = img_N2(:,:,2);
img_N2_B = img_N2(:,:,3);
% figure(); imshow(img_N2_R); title('紅色通道');

img_N1_R = img_N1(:,:,1);
img_N1_G = img_N1(:,:,2);
img_N1_B = img_N1(:,:,3);
% figure(); imshow(img_N2_R); title('紅色通道');

%獲取各個通道的不一樣區域
img_T_R = imabsdiff(img_N2_R,img_N1_R);
T1 = graythresh(img_T_R);
img_D_R = im2bw(img_T_R,T1);%Otus閾值進行分割

img_T_G = imabsdiff(img_N2_G,img_N1_G);
T2 = graythresh(img_T_G);
img_D_G =  im2bw(img_T_G,T2);


img_T_B = imabsdiff(img_N2_B,img_N1_B);
T3 = graythresh(img_T_B);
img_D_B =  im2bw(img_T_B,T3);


img_D = img_D_R + img_D_G  +img_D_B;

se1=strel('disk',1);
se2=strel('disk',3);%disk其實就是一個八邊形
img_N5=imclose(img_D,se2);%通過閉運算
img_N5=imopen(img_D,se1);%通過開運算
K=imclose(img_N5,se2); %獲取到茬所在區域
figure(); imshow(K);title('獲取茬區域塊');



%%繪製標定茬的對比圖
[L, n]=bwlabel(K,8);   %獲取茬連通區域
img_reg = regionprops(L,'area','boundingbox');
areas = [img_reg.Area];
rects = cat(1,img_reg.BoundingBox);
rects = round(rects);

img_L1_T = img_N1;
img_L2_T = img_N2;



%輸出斷定圖框,並在圖框上繪製茬的矩形
%標定左圖茬
for i=1:size(rects,1);
    [state_L1,img_L1_T] = draw_rect(img_L1_T,[rects(i,2),rects(i,1)],[rects(i,3),rects(i,4)]);
end
img_L1 = img_L1_T;


for i=1:size(rects,1);
    [state_L2,img_L2_T] = draw_rect(img_L2_T,[rects(i,2),rects(i,1)],[rects(i,3),rects(i,4)]);
end
img_L2 = img_L2_T;

figure(); imshow(img_L1);
figure(); imshow(img_L2);



% figure('visible','off'); imshow(img_L1_T);
% for i=1:size(rects,1);
%     rectangle('position',rects(i,:),'EdgeColor','r','linewidth',2);
% end
% frame1=getframe(gcf);
% img_L1=frame2im(frame1);
% imwrite(img_L1,'L1.png','png');%能夠修改保存的格式
% 
% 
% figure('visible','off'); imshow(img_L2_T);
% for i=1:size(rects,1);
%     rectangle('position',rects(i,:),'EdgeColor','r','linewidth',2);
% end
% frame2=getframe(gcf);
% img_L2=frame2im(frame2);
% imwrite(img_L2,'L2.png','png');%能夠修改保存的格式
% figure(); imshow(img_L1);
% figure(); imshow(img_L2);



if n>0
    str = sprintf('有茬,茬個數:%d',n);
    title(str, 'Color', 'r'); 
else
     str = sprintf('沒有茬');
     title(str, 'Color', 'g'); 
end

  標定矩形框:

function [state,result]=draw_rect(data,pointAll,windSize,showOrNot)  
% 函數調用:[state,result]=draw_rect(data,pointAll,windSize,showOrNot)  
% 函數功能:在圖像畫個長方形框  
% 函數輸入:data爲原始的大圖,可爲灰度圖,可爲彩色圖  
%          pointAll 框的左上角在大圖中的座標(每行表明一個座標),  
%           注意:在圖中的座標系爲第一列爲y,第二列爲x(很奇怪的)  
%          windSize 框的大小 分別表示長寬  
%          showOrNot 是否要顯示,默認爲顯示出來  
% 函數輸出:state -- 表示程序結果狀態  
%          result - 結果圖像數據   

  
if nargin < 4  
    showOrNot = 0;  
end  
  
rgb = [255 0 0];                                 % 邊框顏色  
lineSize = 2;                                      % 邊框大小,取1,2,3  
  
windSize(1,1)=windSize(1,1);  
windSize(1,2) = windSize(1,2);  
if windSize(1,1) > size(data,1) ||...  
        windSize(1,2) > size(data,2)  
    state = -1;                                     % 說明窗口太大,圖像過小,不必獲取  
    disp('the window size is larger then image...');  
    return;  
end  
  
result = data;  
if size(data,3) == 3 
    for k=1:3  
        for i=1:size(pointAll,1)   %畫邊框順序爲:上右下左的原則  
            result(pointAll(i,1),pointAll(i,2):pointAll(i,2)+windSize(i,1),k) = rgb(1,k);     
            result(pointAll(i,1):pointAll(i,1)+windSize(i,2),pointAll(i,2)+windSize(i,1),k) = rgb(1,k);  
            result(pointAll(i,1)+windSize(i,2),pointAll(i,2):pointAll(i,2)+windSize(i,1),k) = rgb(1,k);    
            result(pointAll(i,1):pointAll(i,1)+windSize(i,2),pointAll(i,2),k) = rgb(1,k);    
            if lineSize == 2 || lineSize == 3  
                result(pointAll(i,1)+1,pointAll(i,2):pointAll(i,2)+windSize(i,1),k) = rgb(1,k);    
                result(pointAll(i,1):pointAll(i,1)+windSize(i,2),pointAll(i,2)+windSize(i,1)-1,k) = rgb(1,k);  
                result(pointAll(i,1)+windSize(i,2)-1,pointAll(i,2):pointAll(i,2)+windSize(i,1),k) = rgb(1,k);  
                result(pointAll(i,1):pointAll(i,1)+windSize(i,2),pointAll(i,2)+1,k) = rgb(1,k);  
                if lineSize == 3  
                    result(pointAll(i,1)+1,pointAll(i,2):pointAll(i,2)+windSize(i,1),k) = rgb(1,k);     
                    result(pointAll(i,1):pointAll(i,1)+windSize(i,2),pointAll(i,2)+windSize(i,1)+1,k) = rgb(1,k);  
                    result(pointAll(i,1)+windSize(i,2)+1,pointAll(i,2):pointAll(i,2)+windSize(i,1),k) = rgb(1,k);  
                    result(pointAll(i,1):pointAll(i,1)+windSize(i,2),pointAll(i,2)+1,k) = rgb(1,k);  
                end  
            end  
        end  
    end  
end  
  
state = 1;  
  
if showOrNot == 1  
    figure;  
    imshow(result);  
end  

%%這個我是直接使用了網上大神寫好的代碼修改一下適應找茬實現
%https://blog.csdn.net/loveaborn/article/details/8545809

  因爲GUI的代碼、GUI界面以及源文件過大,我沒法直接使用博客園分享,因此稍後給出其餘方式分享:

  

  最後我推薦一下博客園裏面很是好的數字圖像處理的數學形態學處理算法基礎的帖子:

  http://www.cnblogs.com/tornadomeet/archive/2012/03/20/2408086.html

  最後,本人初次寫博客,不妥之處望指出,謝謝!

相關文章
相關標籤/搜索