1. 程式人生 > 其它 >別】基於matlab Hough變換鐘錶錶盤識別【含Matlab原始碼 1069期】

別】基於matlab Hough變換鐘錶錶盤識別【含Matlab原始碼 1069期】

一、簡介

霍夫變換(Hough Transform)是影象處理中的一種特徵提取技術,它通過一種投票演算法檢測具有特定形狀的物體。該過程在一個引數空間中通過計算累計結果的區域性最大值得到一個符合該特定形狀的集合作為霍夫變換結果。霍夫變換於1962年由Paul Hough 首次提出[53],後於1972年由Richard Duda和Peter Hart推廣使用[54],經典霍夫變換用來檢測影象中的直線,後來霍夫變換擴充套件到任意形狀物體的識別,多為圓和橢圓。

霍夫變換運用兩個座標空間之間的變換將在一個空間中具有相同形狀的曲線或直線對映到另一個座標空間的一個點上形成峰值,從而把檢測任意形狀的問題轉化為統計峰值問題,上一節中已經介紹了車道的直線特徵,本節中介紹hough變換檢測直線的原理和檢測結果。

我們知道,一條直線在直角座標系下可以用y=kx+b表示, 霍夫變換的主要思想是將該方程的引數和變數交換,即用x,y作為已知量k,b作為變數座標,所以直角座標系下的直線y=kx+b在引數空間表示為點(k,b),而一個點(x1,y1)在直角座標系下表示為一條直線y1=x1·k+b,其中(k,b)是該直線上的任意點。為了計算方便,我們將引數空間的座標表示為極座標下的γ和θ。因為同一條直線上的點對應的(γ,θ)是相同的,因此可以先將圖片進行邊緣檢測,然後對影象上每一個非零畫素點,在引數座標下變換為一條直線,那麼在直角座標下屬於同一條直線的點便在引數空間形成多條直線並內交於一點。因此可用該原理進行直線檢測。

如圖 所示,對於原圖內任一點(x,y)都可以在引數空間形成一條直線,以圖中一條直線為例有引數(γ,θ)=(69.641,30°),所有屬於同一條直線上的點會在引數空間交於一點,該點即為對應直線的引數。由該圖中所有直線所得到的(γ,θ)在引數空間中得到一系列對應曲線見圖 霍夫統計變換結果。

二、原始碼

clear all;
close all;
clc;
P= imread('時鐘-2.jpg');  %2/5/8/11 沒問題 7/10反  13圖分針錯 16圖時針錯

I = imresize(P,0.7);  % 影象縮小70%
% figure('NumberTitle', 'off', 'Name', '原圖');
% imshow(I);
% 去除背景
[m,n]=size(I);
for i=1:m 
    for j=1:n 
        if I(i,j)>100 
            I(i,j)=256; 
        end
    end
end
imshow(I);

I1 = im2bw(I);  %rgb轉化為二值化影象
% figure('NumberTitle', 'off', 'Name', '二值化後圖像');
% imshow(I1);

% I2 = edge(I1,'canny');  %canny 運算元提取邊界
% figure(3)
% imshow(I2)

I20 = imcomplement(I1); %影象反色
% figure('NumberTitle', 'off', 'Name', '反色後圖像');
 imshow(I20);

I2 = bwmorph(I20,'skel',8); %提取影象骨架 6ci   N=6、7、8、9都行  10圖取3  11圖取5
% figure('NumberTitle', 'off', 'Name', '提取影象骨架');
imshow(I2);

%檢測直線
[H,T,R] = hough(I2);  
figure('NumberTitle', 'off', 'Name', '峰值提取效果');
imshow(H,[],'XData',T,'YData',R, 'InitialMagnification','fit');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
P  = houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
x = T(P(:,2)); 
y = R(P(:,1));
plot(x,y,'s','color','white');
% 找出對應的直線邊緣
lines = houghlines(I2,T,R,P,'FillGap',5,'MinLength',7);
total = length(lines);  %檢測出的直線總數
figure, imshow(I2),hold on;
% sec_line = 0; %秒針長度
% min_line = 0; %分針長度
% hour_line = 0; %時針長度
array0=[];  %存放檢測出的直線長度
array1=[];  %排序後的長度

for k = 1:length(lines)
   xy = [lines(k).point1; lines(k).point2];
   plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
   % 標記直線邊緣對應的起點
   plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
   plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
   % 計算直線邊緣長度
   len = norm(lines(k).point1 - lines(k).point2);
   array0(k)=len;
end
%按長度排序,降序排列,前三個數分別是秒針長度、分針長度、時針長度
array1 = sort(array0,'descend');
%找到秒針、分針、時針對應的直線,並算出斜率、角度
for k=1:length(lines)
    xy = [lines(k).point1; lines(k).point2];
    len = norm(lines(k).point1 - lines(k).point2);
    if(len == array1(1))
        sec_line = xy;
        angle_s = lines(k).theta;    %算出的角度是與Y軸負方向的夾角, X軸正向是右,Y軸正向是向下
%        k_s = (xy(2,2)-xy(1,2))/(xy(2,1)-xy(1,1)) %秒針斜率
    end
    if( len == array1(2))
        min_line = xy;
        angle_m = lines(k).theta;
%         k_m = (xy(2,2)-xy(1,2))/(xy(2,1)-xy(1,1))
    end
    if(len  == array1(3))
        hour_line = xy;
        angle_h = lines(k).theta;
%         k_h = (xy(2,2)-xy(1,2))/(xy(2,1)-xy(1,1))
    end      
end
  
%highlight the longest line segment
%plot(xy_long(:,1),xy_long(:,2),'LineWidth',2,'Color','blue')
plot(sec_line(:,1),sec_line(:,2),'LineWidth',2,'Color','b');
plot(min_line(:,1),min_line(:,2),'LineWidth',2,'Color','c');
plot(hour_line(:,1),hour_line(:,2),'LineWidth',2,'Color','r');

%轉換成常用的xy座標系
if(angle_m < 0)
    angle_m= -angle_m + 90;
else
    angle_m = 90 - angle_m;
end

if(angle_h < 0)
    angle_h = -angle_h + 90;
else
    angle_h = 90 - angle_h;
end

if(angle_s < 0)
    angle_s = -angle_s + 90;
else
    angle_s = 90 - angle_s;
end


三、執行結果




四、備註

版本:2014a
完整程式碼或代寫加1564658423