機器視覺與圖像分析(複習題)

一、基礎理論

  1. 採用區域生長法分割下列數字圖像,分別以圖中的灰色點 P(5,3)、Q(5,7)爲起始生長點, 生長準則爲相鄰像素的灰度差不超過 2。畫出分割後的二值圖像,並計算目標區域的面積和歐拉數。
    在這裏插入圖片描述

參考答案: 採用8連通方式時,整張數字圖像所有像素被標記爲灰色。採用4連通方式時,分割後的二值圖像如下圖所示,其中,第1個目標區域的面積爲54個像素面積和,第2個目標區域的面積爲1個像素面積和;二值圖像分析中的歐拉數等於連通組件的個數減去連通組件內部洞(孔)的個數,故兩個目標區域的歐拉數皆爲1。
在這裏插入圖片描述
圖像歐拉數的定義可以參考博文利用OpenCV實現歐拉數的計算

  1. 分別採用4連通或8連通準則,標識出下圖中的目標區域, 並簡要寫出算法步驟。
    在這裏插入圖片描述

參考答案: 算法描述如下。
(1) 設置全局變量v=2v = 2,第一遍逐行掃描像素。若遇到0像素,則直接跳過。否則,根據4連通準則或8連通準則觀察當前像素的鄰居像素,若存在鄰居像素的編號大於1,則以該鄰居像素的編號作爲當前像素的編號;若不存在鄰居像素的編號大於1,則將vv作爲當前像素的編號,同時設置v=v+1v = v + 1,同時需觀察鄰居像素的編號是否存在衝突(產生衝突的2個相鄰像素的編號不同且皆大於1),若存在編號衝突,則在等價表中記錄下這對編號。
(2) 第二遍逐行掃描像素。檢查當前像素的編號是否存在於等價表中,若是,則將當前像素的編號替換成等價關係中最小的那個編號。
在這裏插入圖片描述

  1. 給出圖像中灰色區域的邊界描述:寫出各自的原鏈碼、差分碼和形狀數(※號表示起點像素)。
    在這裏插入圖片描述

參考答案: 原鏈碼、差分碼和形狀數的定義很好理解,認真複習即可。
圖像區域的邊界編碼

區域邊界 圖像A(4方向碼) 圖像B(8方向碼)
原鏈碼 12101010303033232212 322170167665443
差分碼 31331313313130313031 070761151707707
形狀數 03130313133131331313 070707611517077
  1. 通過文獻閱讀和分析,闡明張正友相機標定方法的原理、步驟與特點。若已知一個相機的標定矩陣,如何確定其內外部參數?

參考答案: 相機成像系統中,共包含四個座標系:世界座標系、相機座標系、圖像座標系、像素座標系,四個座標系關係如下圖所示,
在這裏插入圖片描述
這四個座標系之間的轉化關係爲

Z(uv1)=(1dXcotθdXu001dYsinθv0001)(f0000f000010)(r00r01r02t0r10r11r12t1r20r21r22t20001)(UVW1) Z \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} = \begin{pmatrix} \frac{1}{dX} & -\frac{\cot \theta}{dX} & u_0 \\ 0 & \frac{1}{dY \sin \theta} & v_0 \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} f & 0 & 0 & 0 \\ 0 & f & 0 & 0 \\ 0 & 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} r_{00} & r_{01} & r_{02} & t_0 \\ r_{10} & r_{11} & r_{12} & t_1 \\ r_{20} & r_{21} & r_{22} & t_2 \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} U \\ V \\ W \\ 1 \end{pmatrix}

其中(U,V,W)(U, V, W)爲在世界座標系下一點的物理座標,(u,v)(u, v)爲該點對應的在像素座標系下的像素座標,ZZ爲尺度因子。此外,
(1dXcotθdXu001dYsinθv0001)(f0000f000010)=(fdXfcotθdXu00fdYsinθv0001) \begin{pmatrix} \frac{1}{dX} & -\frac{\cot \theta}{dX} & u_0 \\ 0 & \frac{1}{dY \sin \theta} & v_0 \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} f & 0 & 0 & 0 \\ 0 & f & 0 & 0 \\ 0 & 0 & 1 & 0 \end{pmatrix} = \begin{pmatrix} \frac{f}{dX} & -\frac{f \cot \theta}{dX} & u_0 \\ 0 & \frac{f}{dY \sin \theta} & v_0 \\ 0 & 0 & 1 \end{pmatrix}
爲相機的內參矩陣,其中ff爲像距,dX,dYdX, dY分別爲X,YX, Y方向上的一個像素在相機感光板上的物理長度,u0,v0u_0, v_0分別表示相機感光板中心在像素座標系下的座標,θ\theta表示感光板的XX軸和YY軸之間的夾角(理想情況下θ=90°\theta = 90 \degree)。而矩陣
(r00r01r02t0r10r11r12t1r20r21r22t20001)=(R3×3T3×101×31) \begin{pmatrix} r_{00} & r_{01} & r_{02} & t_0 \\ r_{10} & r_{11} & r_{12} & t_1 \\ r_{20} & r_{21} & r_{22} & t_2 \\ 0 & 0 & 0 & 1 \end{pmatrix} = \begin{pmatrix} \bm{R}_{3 \times 3} & \bm{T}_{3 \times 1} \\ \bm{0}_{1 \times 3} & 1 \end{pmatrix}
爲相機的外參矩陣,R\bm{R}爲旋轉矩陣,右下角3×33 \times 3表示矩陣維度3行3列,T\bm{T}爲平移矢量。上述座標系關係具體推導可參考:https://www.cnblogs.com/zyly/p/9366080.html

原理: 張正友教授將世界座標系固定於西洋棋棋盤上,並假設W=0W = 0。由於西洋棋棋盤的世界座標系是人爲事先定義好的,且每一個格子的大小已知,通過計算可得到每一個角點在世界座標系下的物理座標(U,V,W=0)(U, V, W = 0)。通過圖像識別與匹配,可進一步得到每一個角點的像素座標(u,v)(u, v)。我們利用成對的物理座標和像素座標來求解相機的標定矩陣(內參矩陣與外參矩陣的積),進而求解內參矩陣和外參矩陣。原理的具體推導可參考:https://zhuanlan.zhihu.com/p/94244568https://blog.csdn.net/qq_40369926/article/details/89251296

步驟: 打印一張西洋棋棋盤模板貼在一個固定的平面上;從不同角度拍攝若干張模板圖像,檢測出圖像中的角點並記錄成對的物理座標與像素座標;求解理想無畸變情況下的相機內參和外參,並用極大似然估計法優化估計值;應用最小二乘法求出實際的徑向畸變係數;綜合內參、外參和畸變係數,使用極大似然法優化估計值,提升估計精度,最終輸出相機內參、外參和畸變係數。

特點: 傳統標定法需要精確製作的三維標定板來完成標定工作。張正友教授提出的方法介於傳統標定法和自標定法之間,該方法克服了傳統標定法需要的高精度標定板的缺點,它僅需打印一個西洋棋棋盤模板即可完成標定工作;此外,相對於自標定法而言,該方法提高了標定精度。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
注意. 這裏的外參矩陣是相對外參

  1. 如圖,已知物點Q在左相機中的像點a (xa,ya)(x_a, y_a)的數字圖像座標爲(ul,vl)(u_l, v_l), 試確定在右相機成像平面中與像點a (xa,ya)(x_a, y_a)對應的像點b (xb,yb)(x_b, y_b)的位置範圍(繪圖示意)。假定兩個相機的標定矩陣MlM_lMrM_r已知,試給出求解像點b數字圖像座標(ur,vr)(u_r,v_r)的方法和步驟。

在這裏插入圖片描述

參考答案: 僅知道像點a的數字圖像座標,無法確切知道物點Q的物理座標,因此Q有可能是射線aQ上的某一點。連接像點a與右相機的光心,得到像點pap_a;接着連接像點a與像點pap_a至右相機成像平面邊界線,紅色線即像點b的位置範圍。
在這裏插入圖片描述

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

極線ll十分有用,在右圖像上用模板匹配尋找點(ur,vr)(u_r, v_r)屬於暴力搜索較爲耗時,且可能存在多個相似點,加上極線ll約束後就可以減少耗時且篩選無關相似點。確定了左、右相機的成像點座標(ul,vl)(u_l, v_l)(ur,vr)(u_r, v_r),就可以估計點Q的大致世界座標。

認真聽課,題目大致都可以做的出來。

二、綜合應用

  1. 圖1是一張大米籽粒圖片,試設計適當的圖像分析算法統計其中顯示完整的大米粒數;並找出其中體積最大的米粒位置(標註出其質心位置)。

在這裏插入圖片描述
參考答案: 以下是matlab代碼,

close all; 
clear all;
clc;

I = imread('images/MV2001.png');

% 消除光照不均的圖像處理(形態學濾波)
background = imopen(I, strel('disk',15));
I2 = I - background;
% figure, subplot(121), imshow(I2), title('消除光照影響後的圖像');
% subplot(122), imhist(I2), title('光照處理圖像的直方圖')
% 圖像增強
I3 = imadjust(I2);
% figure, imshow(I3); title('對比度增強後的處理圖像');

% 全局閾值分割
% figure, imhist(I3); title('增強處理圖像的直方圖'); % 直方圖分析
bw = (I3 > 130);
bw = bwareaopen(bw, 50); % 消除二值圖像中面積小於50的對象

% 顯示分割結果
% figure, subplot(121), imshow(I), title('原始圖像');
% subplot(122), imshow(bw), title('光照處理的全局閾值分割');

% 進行二次分割
% 在一次分割基礎上檢測米粒邊緣以消除細小黏連部分
Ik = bw;
hy = fspecial('prewit');
hx = hy';
Iy = imfilter(double(Ik), hy, 'replicate');
Ix = imfilter(double(Ik), hx, 'replicate');
% 分水嶺分割法
gradmag = sqrt(Ix.^2 + Iy.^2);
L = watershed(gradmag);
Lrgb = label2rgb(L, 'spring', 'c', 'shuffle');
% figure, imshow(Lrgb);

% 消除面積小於40的對象
num_of_regions = max(max(L));
J = zeros(size(L));
% 編號0是背景,編號1是邊界,故從2開始循環
for i = 2:num_of_regions
    if sum(sum(L == i)) >= 40
        J(L == i) = 1;
    end
end

% figure, imshow(J);

% 統計連通區域,一塊連通區域即一粒大米
[r, num] = bwlabel(J, 8);
% 打印米粒個數
disp(['完整大米的粒數:', num2str(max(max(r)))]);

% 在原圖中繪製邊界框
rects = regionprops(r, 'boundingbox');
rects = cat(1, rects.BoundingBox);  
figure, imshow(I);
for i = 1:size(rects, 1)
    rectangle('position', rects(i, :), 'Edgecolor', 'y', 'LineWidth', 1);  
end

% 找出體積最大的米粒的位置(標註出其質心位置)
% 找出體積最大的米粒的編號
max_size = 0;
max_size_index = 0;
for i = 1:num
    size_i = sum(sum(r == i));
    if size_i > max_size
        max_size = size_i;
        max_size_index = i;
    end
end
% 計算質心位置
seg_of_max_size = (r == max_size_index);
t_x = zeros(size(r));
t_y = zeros(size(r));
[y_len, x_len] = size(r);
for x = 1:x_len
    t_x(:, x) = x .* seg_of_max_size(:, x);
end
for y = 1:y_len
    t_y(y, :) = y .* seg_of_max_size(y, :);
end
c_x = sum(sum((r == max_size_index) .* t_x)) / max_size;
c_y = sum(sum((r == max_size_index) .* t_y)) / max_size;
disp(['最大米粒的質心位置', '(', num2str(c_x), ',', num2str(c_y), ')']);
hold on;
plot(c_x, c_y, 'r.', 'MarkerSize', 20);

figure, subplot(1, 2, 1), imshow(I);
subplot(1, 2, 2), imshow(I);
for i = 1:size(rects, 1)
    rectangle('position', rects(i, :), 'Edgecolor', 'y', 'LineWidth', 1);  
end
hold on
plot(c_x, c_y, 'r.', 'MarkerSize', 20);

% 一次分割與二次分割的對比
% figure, subplot(1, 3, 1), imshow(I), title('原圖');
% [bw_r, bw_n] = bwlabel(bw, 8);
% bwrgb = label2rgb(bw_r, 'spring', 'c', 'shuffle');
% subplot(1, 3, 2), imshow(bwrgb), title('一次分割');
% subplot(1, 3, 3), imshow(Lrgb), title('二次分割');

% 直接在原圖上使用分水嶺分割的結果
% Ik = I;
% hy = fspecial('prewit');
% hx = hy';
% Iy = imfilter(double(Ik), hy, 'replicate');
% Ix = imfilter(double(Ik), hx, 'replicate');
% % 分水嶺分割法
% gradmag = sqrt(Ix.^2 + Iy.^2);
% L = watershed(gradmag);
% Lrgb = label2rgb(L, 'spring', 'c', 'shuffle');
% figure, imshow(Lrgb), title('直接使用分水嶺分割');

運行效果圖
在這裏插入圖片描述
在這裏插入圖片描述

  1. 圖2是一幅動物圖像,試分別採用K-Means和Mean Shift算法實現對目標區域的分割;並分析兩種算法各自的優缺點。
    在這裏插入圖片描述

參考答案: K-Means算法原理:https://www.jianshu.com/p/e4d5a0fbcefe,和Mean Shift算法原理:https://blog.csdn.net/hjimce/article/details/45718593。K-Means算法和Mean Shift算法都是聚類算法,通過將前景像素聚爲一個類簇、將背景像素聚爲一個類簇,從而實現圖像分割。爲了完成像素的聚類,需要提取像素的特徵,可以從顏色、空間等方面入手設計特徵提取器。

開源代碼可直接從Matlab社區下載:https://www.mathworks.com/matlabcentral/fileexchange/52698-k-means-mean-shift-and-normalized-cut-segmentation,Overview頁面是算法接口說明,Functions頁面是詳細代碼。

Km.m

function Ikm = Km(I, K) 
% K-means Segmentation (option: K (Number of Clusters))
I = im2double(I);
F = reshape(I, size(I, 1) * size(I, 2), 3);             % Color Features
% K-means
CENTS = F(ceil(rand(K, 1) * size(F, 1)), :);            % Cluster Centers
DAL = zeros(size(F, 1), K + 2);                         % Distances and Labels
KMI = 10;                                               % K-means Iteration
for n = 1:KMI
   for i = 1:size(F, 1)
      for j = 1:K  
        DAL(i, j) = norm(F(i, :) - CENTS(j, :));      
      end
      [Distance, CN] = min(DAL(i, 1:K));                % 1:K are Distance from Cluster Centers 1:K 
      DAL(i, K + 1) = CN;                               % K+1 is Cluster Label
      DAL(i, K + 2) = Distance;                         % K+2 is Minimum Distance
   end
   for i = 1:K
      A = (DAL(:, K + 1) == i);                         % Cluster K Points
      CENTS(i, :) = mean(F(A, :));                      % New Cluster Centers
      if sum(isnan(CENTS(:))) ~= 0                      % If CENTS(i,:) Is Nan Then Replace It With Random Point
         NC = find(isnan(CENTS(:, 1)) == 1);            % Find Nan Centers
         for Ind = 1:size(NC, 1)
            CENTS(NC(Ind), :) = F(randi(size(F, 1)), :);
         end
      end
   end
end
X = zeros(size(F));
for i = 1:K
    idx = find(DAL(:, K + 1) == i);
    X(idx, :) = repmat(CENTS(i, :), size(idx, 1), 1); 
end
Ikm = reshape(X, size(I, 1), size(I, 2), 3);
end

MeanShiftCluster.m

function [clustCent, data2cluster, cluster2dataCell] = MeanShiftCluster(dataPts, bandWidth, plotFlag)
% perform MeanShift Clustering of data using a flat kernel
%
% ---INPUT---
% dataPts           - input data, (numDim x numPts)
% bandWidth         - is bandwidth parameter (scalar)
% plotFlag          - display output if 2 or 3 D    (logical)
% ---OUTPUT---
% clustCent         - is locations of cluster centers (numDim x numClust)
% data2cluster      - for every data point which cluster it belongs to (numPts)
% cluster2dataCell  - for every cluster which points are in it (numClust)
%
% Bryan Feldman 02/24/06
% MeanShift first appears in
% K. Funkunaga and L.D. Hosteler, "The Estimation of the Gradient of a
% Density Function, with Applications in Pattern Recognition"
%*** Check input ****
if nargin < 2
    error('no bandwidth specified')
end
if nargin < 3
    plotFlag = false;
end
%**** Initialize stuff ***
[numDim, numPts] = size(dataPts);
numClust        = 0;
bandSq          = bandWidth^2;
initPtInds      = 1:numPts;
maxPos          = max(dataPts, [], 2);                  % biggest size in each dimension
minPos          = min(dataPts, [], 2);                  % smallest size in each dimension
boundBox        = maxPos - minPos;                      % bounding box size
sizeSpace       = norm(boundBox);                       % indicator of size of data space
stopThresh      = 1e-3 * bandWidth;                     % when mean has converged
clustCent       = [];                                   % center of clust
beenVisitedFlag = zeros(1, numPts, 'uint8');            % track if a points been seen already
numInitPts      = numPts;                               % number of points to posibaly use as initilization points
clusterVotes    = zeros(1, numPts, 'uint16');           % used to resolve conflicts on cluster membership
while numInitPts
    tempInd = ceil((numInitPts - 1e-6) * rand);         % pick a random seed point
    stInd = initPtInds(tempInd);                        % use this point as start of mean
    myMean = dataPts(:, stInd);                         % intilize mean to this points location
    myMembers = [];                                     % points that will get added to this cluster
    thisClusterVotes = zeros(1, numPts, 'uint16');      % used to resolve conflicts on cluster membership
    while 1     %loop untill convergence
        sqDistToAll = sum((repmat(myMean, 1, numPts) - dataPts).^2);	% dist squared from mean to all points still active
        inInds = find(sqDistToAll < bandSq);	%points within bandWidth
        thisClusterVotes(inInds) = thisClusterVotes(inInds) + 1;	% add a vote for all the in points belonging to this cluster
        
        myOldMean = myMean;                     % save the old mean
        myMean = mean(dataPts(:, inInds), 2);	% compute the new mean
        myMembers = [myMembers inInds];         % add any point within bandWidth to the cluster
        beenVisitedFlag(myMembers) = 1;         % mark that these points have been visited
        
        %*** plot stuff ****
        if plotFlag
            figure(12345), clf, hold on
            if numDim == 2
                plot(dataPts(1, :), dataPts(2, :), '.')
                plot(dataPts(1, myMembers), dataPts(2, myMembers), 'ys')
                plot(myMean(1), myMean(2), 'go')
                plot(myOldMean(1), myOldMean(2), 'rd')
                pause(.1)
            end
        end
        %**** if mean doesn't move much stop this cluster ***
        if norm(myMean - myOldMean) < stopThresh
            % check for merge posibilities
            mergeWith = 0;
            for cN = 1:numClust
                distToOther = norm(myMean - clustCent(:, cN));	% distance from posible new clust max to old clust max
                if distToOther < bandWidth / 2                  %if its within bandwidth/2 merge new and old
                    mergeWith = cN;
                    break;
                end
            end            
            
            if mergeWith > 0	% something to merge
                clustCent(:,mergeWith) = 0.5*(myMean+clustCent(:,mergeWith));                   % record the max as the mean of the two merged (I know biased twoards new ones)
                % clustMembsCell{mergeWith} = unique([clustMembsCell{mergeWith} myMembers]);	% record which points inside
                clusterVotes(mergeWith, :) = clusterVotes(mergeWith, :) + thisClusterVotes;     % add these votes to the merged cluster
            else	% its a new cluster
                numClust = numClust+1;                  % increment clusters
                clustCent(:, numClust) = myMean;        % record the mean
                % clustMembsCell{numClust} = myMembers;	%store my members
                clusterVotes(numClust, :) = thisClusterVotes;
            end
            break;
        end
    end
    
    initPtInds = find(beenVisitedFlag == 0);        % we can initialize with any of the points not yet visited
    numInitPts = length(initPtInds);                % number of active points in set
end
[val, data2cluster] = max(clusterVotes, [], 1);     % a point belongs to the cluster with the most votes
%*** If they want the cluster2data cell find it for them
if nargout > 2
    cluster2dataCell = cell(numClust, 1);
    for cN = 1:numClust
        myMembers = find(data2cluster == cN);
        cluster2dataCell{cN} = myMembers;
    end
end
end

Ms.m

function [Ims, Kms] = Ms(I, bandwidth)
% Mean Shift Segmentation (option: bandwidth)
I = im2double(I);
X = reshape(I, size(I, 1) * size(I, 2), 3); % Color Features
% MeanShift
[clustCent, point2cluster, clustMembsCell] = MeanShiftCluster(X', bandwidth);	% MeanShiftCluster
for i = 1:length(clustMembsCell)	% Replace Image Colors With Cluster Centers
    X(clustMembsCell{i}, :) = repmat(clustCent(:, i)', size(clustMembsCell{i}, 2), 1); 
end
Ims = reshape(X, size(I, 1), size(I, 2), 3);	% Segmented Image
Kms = length(clustMembsCell);
end

main.m

clc;
clear all;
close all;

% input
I = imread('images/MV2003.png');

% parameters
% K-means parameter
K = 2;          % Cluster Numbers
% Mean-Shift parameter
bw = 0.2;               % Mean-Shift Bandwidth

% segmentation
% K-means
Ikm = Km(I, K);	% Kmeans (color)
% Mean-Shift
[Ims, Nms] = Ms(I, bw);	% Mean-Shift (color)

% show
figure, subplot(1, 3, 1), imshow(I), title('原圖');
subplot(1, 3, 2), imshow(Ikm), title('K-Means分割結果(k = 2)');
subplot(1, 3, 3), imshow(Ims), title('Mean Shift分割結果');

運行效果圖
在這裏插入圖片描述

Reference

提取二值圖中連通域的包圍框 matlab
MATLAB中用rectangle在圖像上畫出個矩形,線的顏色默認是黑色,怎麼去改變它?
Convert label matrix into RGB image
MATLAB:regionprops函數求取最大連通域面積

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