https://www.yuque.com/lart/papershtml
本文不是按照以前的論文那樣, 考慮顯著性目標與背景之間的對比度, 而是經過使用流形排序方法, 來使用前景/背景線索對圖像元素(像素或者區域)進行排序. node
在這種方法中, 圖像元素的顯著性是基於它們與給定種子/查詢的相關性來定義的.python
咱們將圖像表示爲一個以超像素爲節點的閉環圖。這些節點的排序是基於與背景和前景查詢的類似性,基於關聯矩陣(affinity matrices)。採用兩階段的顯著性檢測方法,有效地提取背景區域和前景顯著目標。git
同時本文也構建了一個大規模的數據集, 來進行顯著性檢測的測試評估.github
本篇論文主要專一的是一種由下而上的方法. 算法
主要相關的幾個方法結論或者觀察.app
這篇文章中, 使用這些線索基於超像素的排序來計算像素的顯著性.less
從這個流程中, 能夠關注幾個點:dom
基於圖的流形排序, 被描述爲: 給定一個節點做爲查詢. 剩餘節點基於與這個給定節點之間的相關性來進行排序. 目標是學習一個定義了未標記節點與查詢之間的相關性的流形函數.函數
也就是說, 文中的基於圖的流行排序實際上就是經過一個流行函數定義未標記節點與查詢節點之間的相關性. 如果有了這個與前景或者背景查詢節點的相關性, 就能夠用來排序, 與前景相關性高的就能夠用其表示顯著性, 與背景相關性高的, 就能夠用其表示非顯著性(1-f能夠用來表示顯著性).(具體細節見後).
論文[D. Zhou, J. Weston, A. Gretton, O. Bousquet, and B. Scholkopf. Ranking on data manifolds_. In NIPS, 2004_]提出了一種利用數據(如圖像)固有流形結構進行圖形標籤排序的方法.
爲何要建模成流行排序問題?
爲了充分捕捉圖的內在結構信息,並在圖的標註中加入局部分組線索(local grouping),咱們利用流形排序技術(manifold ranking)來學習排序函數,這對於學習最優親和矩陣是相當重要的.
對於該問題的建模以下:
主要是將映射 表示爲一個排序問題. 賦予一個排序值到每一個點數據點 上, 彙總獲得的 ,做爲最終獲得的排序值.
將圖片表示爲一個無向圖結構, 節點爲超像素, 而邊的權重整體表示爲關聯矩陣 , 對應的圖所對應的度矩陣表示爲 這裏的d對應於W特定行之和. 反映了和特定節點鏈接的其餘全部節點邊的權重之和. 這個也在必定程度上能夠認爲是一種節點之間的相關程度/關聯性. 這裏計算顯著性就是用它.
是否能夠表示爲有向圖, 這樣能夠表示更爲豐富的信息, 好比特徵之間的依賴性, 不過感受這個想法不適合與這樣的自下而上的傳統方法, 由於這種有向的依賴關係, 對應的特徵應該是更爲高級的語義信息.
這裏讓我想到了分割的一個結構, DD-RNN和DAG-RNN
爲了找到最好的一個排序, 這裏將這個優化問題表述爲:
從式子1能夠了解到
最小解, 利用導數求解, 獲得結果以下, 式子2是最終的排序結果對應的函數. 而式子3使用的是未標準化的拉普拉斯矩陣.
具體參數可見前面圖片的定義. 實際使用的是式子3. 這裏是測試比較:
The figure shows that the ranking results with the unnormalized Laplacian matrix are better, and used in all the experiments.
這裏有一點, 文中沒有細說, 最終的排序是對f中的元素進行排序, 仍是說f中的元素實際上已經排好序了 (這裏劃掉的部分, 能夠如此理解並推翻: f的索引實際上與y的索引是對應的, 也就是說,** f表示的是特定節點到全部查詢點之間的相關性之和**. 因此說, 若是索引固定, 那麼這裏應該是基於獲得的f來計算對應的顯著性值.)
實際上這裏說是排序, 其實並無進行排序操做, 只是利用這個優化問題獲得的相關性解, 來進行顯著性值的計算. 雖然這個值在必定程度上反映了顯著性的排序狀況, 可是並無具體用到排序的操做
關於式子2, 3. 兩者的差異, 前者是用的是標準化參數, 後者使用的是更爲直接的參數. 而在計算顯著性的時候, 是須要進行標準化的, 因此使用3式的時候, 仍是要進行標準化處理的. .
這裏的標準化是將數據放縮到了0~1範圍, 能夠看下面的代碼示例:
bsalt=optAff*Yt; bsalt=(bsalt-min(bsalt(:)))/(max(bsalt(:))-min(bsalt(:)));
傳統的排序問題, 查詢是要手動用真實標記的. 然而提出的算法選擇的查詢, 一些可能被標錯了. 所以須要對每一個查詢計算一個置信度(也就是顯著性值), 這個用它的排序得分, 這是經過其餘查詢計算出來的(排除自身).
最後, 設定A中的對角元素爲0. 這個看似可有可無的過程對最終結果有很大的影響, 這裏 若是沒有設置A的對角元素爲0來進行計算每個查詢的顯著性的時候, 結果會包含查詢與自身的相關性, 這個一般很大 (是同一行其餘項的和的負數), 會嚴重抑制其餘查詢對於排序得分的貢獻.
由於度矩陣D的對角元素是仿射矩陣W的每行元素的和. 若是D不設定爲0, 那麼差值以後, 就會減掉自身的影響.
關於權重w, 有以下設定:
節點之間的權重使用顏色空間的距離的鐘形函數來進行建模. 方差項用來控制權重的強度. 色彩距離(差別)越大, 賦予的權重也就越小.
這裏提到了兩點:
因爲相鄰節點可能具備類似的外觀和顯著性值,使用_k-regular_圖來利用空間關係。
經過對邊的約束,能夠看出構造圖是稀疏鏈接的。也就是說,關聯矩陣 的大部分項都是零。
這裏爲何是稀疏鏈接的? 雖然從結果上來看確實是稀疏的. 可見參考連接裏的
SLIC算法測試
, 裏面有一些測試.
這裏能夠看python代碼計算W和D的部分, 有一段:W = sp.exp(-1*W / self.weight_parameters['delta']) # 歸屬於不一樣超像素的像素之間, 不相鄰的賦予0 W[adj.astype(np.bool)] = 0這裏是反着取得鄰接矩陣, 因此, 不相鄰的部分對應的關聯矩陣W是要置0的. 而這裏的鄰接矩陣, 在這裏指定的關於鄰接的約束, 致使大部分節點之間是不相鄰的. 因此這裏adj是稀疏的, 致使W也是一個稀疏矩陣.
根據早期關於視覺顯著性[17]的注意理論,咱們將圖像邊界上的節點做爲背景種子,即,將標記的數據(查詢樣本)對全部其餘區域的相關性進行排序。具體地說,咱們使用邊界先驗構造了四個顯著性圖,而後將它們集成到最終的映射中,這被稱爲分離/組合(SC)方法.
以圖像頂部邊界爲例,使用這一側的節點做爲查詢,其餘節點做爲未標記的數據。所以, 指示向量y被給定, 全部的節點是基於式子3中的_f∗_排名, 這是一個N維向量(N是圖的節點總數)。此向量中的每一個元素表示節點與背景查詢節點的相關性, 其關於1的補數是顯著性測量.
相似的計算其餘三邊的狀況. 注意, 實際上, 在這個過程當中, 矩陣D, W只須要計算一次, 而y都是能夠肯定的.
最後進行集成:
使用相乘的方法來進行集成. 這裏有點相似於同一年的Graph-Regularized Saliency Detection
With Convex-Hull-Based Center Prior文章中集成對比度先驗與基於凸包的中心先驗的方法.
- 這種經過相乘的方式來進行集成的方式來自哪裏? * 還有沒有其餘的集成的方式?
使用SC方法的主要的考慮是四邊同時使用的效果很差, 主要體如今兩個方面:
對比結果以下圖:
進一步基於前景查詢排序來優化結果, 主要是爲了應對目標出如今靠近圖像邊緣的狀況.
第一階段的顯著性映射是二值分割的(即,突出的前景和背景), 使用一個自適應閾值,這有助於選擇節點的前景顯著性目標做爲查詢節點。咱們指望選擇的查詢儘量地覆蓋突出的對象區域(即)。所以,閾值被設置爲整個顯著性映射的平均顯著性。
相似的, 這裏則直接可使用與查詢節點計算相關性來得到顯著性值:
這裏就不用互補計算了, 由於這裏是算的與前景的相關性.
顯著目標區域一般是相對緊湊的(在空間分佈方面)和均勻的外觀(在特徵分佈方面),而背景區域正好相反。換句話說,對象內部的相關性(即,顯著對象的兩個節點)在統計上遠大於對象背景和背景內相關性,能夠從關聯矩陣A中推斷。爲了進一步顯示這個現象, 文章從數據集真值中, 進行了測試:
To show this phenomenon, we compute the average intra-object, intra-background and object-background relevance values in A for each of the 300 images sampled from a dataset with ground truth labels.
從真值標記統計出來, 明顯能夠看出來, 目標節點到全部真值的顯著性查詢的相關性之和要大於背景節點到全部查詢的相關性之和. 這個是最優狀態的A的結果對應的解釋.
可是這個可以說明這個方法中的背景是能夠被有效抑制的麼? 能夠的.
由於A是最終的的f的一個仿射變換矩陣, 其中的值對應着f的結果, 也就是對應着最終的顯著性結果.
這裏用實驗解釋了目標內部相關性是最大的. 而這個結論在使用前景查詢進行優化提高的時候, 在必定程度上能夠改善已經預測的顯著性區域. 由於_通常顯著性目標對象區域更爲緊湊, 均勻. 在計算距離的時候, 周圍的一致性更強, 鑑於色彩空間加權的做用, 最終與相關性值會更高一些. 而先前錯誤標記的部分, 相對而言值更小了_.
A是基於原始圖像的色彩的. 從一開始就是個定值. 查詢的選擇, 影響的是y.
主要流程:
https://github.com/huchuanlu/13_4/blob/master/demo.m
https://github.com/ruanxiang/mr_saliency/blob/master/MR/MR.py(主要從這裏入手理解), python版本的實現與matlab實現細節有些差別, 主要是在於裏面對於第一階段的計算中, python版本是反着來的, 它把背景(邊界)的指示值設定爲了1, 最後集成的時候又用1算了個補數. 而matlab的流程設定和論文是一致的.
% Demo for paper "Saliency Detection via Graph-Based Manifold Ranking" % by Chuan Yang, Lihe Zhang, Huchuan Lu, Ming-Hsuan Yang, and Xiang Ruan % To appear in Proceedings of IEEE Conference on Computer Vision and Pattern Recognition (CVPR 2013), Portland, June, 2013. clear all; addpath('./others/'); %%------------------------set parameters---------------------%% theta=10; % control the edge weight alpha=0.99;% control the balance of two items in manifold ranking cost function spnumber=200;% superpixel number imgRoot='./test/';% test image path saldir='./saliencymap/';% the output path of the saliency map supdir='./superpixels/';% the superpixel label file path mkdir(supdir); mkdir(saldir); imnames=dir([imgRoot '*' 'jpg']); % 迭代圖片 for ii=1:length(imnames) disp(ii); imname=[imgRoot imnames(ii).name]; [input_im,w]=removeframe(imname);% run a pre-processing to remove the image frame [m,n,k] = size(input_im); %%----------------------generate superpixels使用SLIC方法來生成超像素--------------------%% imname=[imname(1:end-4) '.bmp'];% the slic software support only the '.bmp' image comm=['SLICSuperpixelSegmentation' ' ' imname ' ' int2str(20) ' ' int2str(spnumber) ' ' supdir]; system(comm); spname=[supdir imnames(ii).name(1:end-4) '.dat']; % 得到超像素標記矩陣 superpixels=ReadDAT([m,n],spname); % superpixel label matrix spnum=max(superpixels(:));% the actual superpixel number %%----------------------design the graph model 計算聚攏的像素在lab顏色空間中的平均值--------------------------%% % compute the feature (mean color in lab color space) % for each node (superpixels) input_vals=reshape(input_im, m*n, k); rgb_vals=zeros(spnum,1,3); inds=cell(spnum,1); for i=1:spnum inds{i}=find(superpixels==i); rgb_vals(i,1,:)=mean(input_vals(inds{i},:),1); end lab_vals = colorspace('Lab<-', rgb_vals); seg_vals=reshape(lab_vals,spnum,3);% feature for each superpixel % get edges 獲取節點之間的邊 adjloop=AdjcProcloop(superpixels,spnum); edges=[]; for i=1:spnum indext=[]; ind=find(adjloop(i,:)==1); for j=1:length(ind) indj=find(adjloop(ind(j),:)==1); indext=[indext,indj]; end indext=[indext,ind]; indext=indext((indext>i)); indext=unique(indext); if(~isempty(indext)) ed=ones(length(indext),2); ed(:,2)=i*ed(:,2); ed(:,1)=indext; edges=[edges;ed]; end end % compute affinity matrix 計算關聯矩陣, 表示了各類權重關係 weights = makeweights(edges,seg_vals,theta); W = adjacency(edges,weights,spnum); % learn the optimal affinity matrix (eq. 3 in paper) 學習最優的關聯矩陣 % 這裏是設定了一個稀疏矩陣. % 使用i=1:spnum和j=1:spnum指定的座標, 賦予特定的值dd, 也就是D(i(k), j(k))=dd(k) % 獲得的結果中, dd = sum(W); D = sparse(1:spnum,1:spnum,dd); clear dd; optAff =(D-alpha*W)\eye(spnum); mz=diag(ones(spnum,1)); mz=~mz; optAff=optAff.*mz; %%-----------------------------stage 1--------------------------%% % compute the saliency value for each superpixel % with the top boundary as the query Yt=zeros(spnum,1); bst=unique(superpixels(1,1:n)); Yt(bst)=1; bsalt=optAff*Yt; bsalt=(bsalt-min(bsalt(:)))/(max(bsalt(:))-min(bsalt(:))); bsalt=1-bsalt; % down Yd=zeros(spnum,1); bsd=unique(superpixels(m,1:n)); Yd(bsd)=1; bsald=optAff*Yd; bsald=(bsald-min(bsald(:)))/(max(bsald(:))-min(bsald(:))); bsald=1-bsald; % right Yr=zeros(spnum,1); bsr=unique(superpixels(1:m,1)); Yr(bsr)=1; bsalr=optAff*Yr; bsalr=(bsalr-min(bsalr(:)))/(max(bsalr(:))-min(bsalr(:))); bsalr=1-bsalr; % left Yl=zeros(spnum,1); bsl=unique(superpixels(1:m,n)); Yl(bsl)=1; bsall=optAff*Yl; bsall=(bsall-min(bsall(:)))/(max(bsall(:))-min(bsall(:))); bsall=1-bsall; % combine bsalc=(bsalt.*bsald.*bsall.*bsalr); bsalc=(bsalc-min(bsalc(:)))/(max(bsalc(:))-min(bsalc(:))); % 這時 ,bsalc是第一階段最終的顯著性標記 % assign the saliency value to each pixel 爲每一個像素分配顯著性值 tmapstage1=zeros(m,n); for i=1:spnum tmapstage1(inds{i})=bsalc(i); end tmapstage1=(tmapstage1-min(tmapstage1(:)))/(max(tmapstage1(:))-min(tmapstage1(:))); mapstage1=zeros(w(1),w(2)); mapstage1(w(3):w(4),w(5):w(6))=tmapstage1; mapstage1=uint8(mapstage1*255); outname=[saldir imnames(ii).name(1:end-4) '_stage1' '.png']; imwrite(mapstage1,outname); %%----------------------stage2-------------------------%% % binary with an adaptive threhold (i.e. mean of the saliency map) 自適應閾值二值化, 閾值被設置爲整個顯著圖上的平均顯著性 th=mean(bsalc); bsalc(bsalc<th)=0; bsalc(bsalc>=th)=1; % compute the saliency value for each superpixel fsal=optAff*bsalc; % assign the saliency value to each pixel tmapstage2=zeros(m,n); for i=1:spnum tmapstage2(inds{i})=fsal(i); end tmapstage2=(tmapstage2-min(tmapstage2(:)))/(max(tmapstage2(:))-min(tmapstage2(:))); mapstage2=zeros(w(1),w(2)); mapstage2(w(3):w(4),w(5):w(6))=tmapstage2; mapstage2=uint8(mapstage2*255); outname=[saldir imnames(ii).name(1:end-4) '_stage2' '.png']; imwrite(mapstage2,outname); end
#################################################################### ## Author: ## Xiang Ruan ## httpr://ruanxiang.net ## ruanxiang@gmail.com ## License: ## GPL 2.0 ## NOTE: the algorithm itself is patented by OMRON, co, Japan ## my previous employer, so please do not use the algorithm in ## any commerical product ## Version: ## 1.0 ## ## ---------------------------------------------------------------- ## A python implementation of manifold ranking saliency ## Usage: ## import MR ## import matplotlib.pyplot as plt ## mr = MR.MR_saliency() ## sal = mr.saliency(img) ## plt.imshow(sal) ## plt.show() ## ## Check paper.pdf for algorithm details ## I leave all th parameters open to maniplating, however, you don't ## have to do it, default values work pretty well, unless you really ## know what you want to do to modify the parameters import scipy as sp import numpy as np import cv2 from skimage.segmentation import slic from skimage.segmentation import mark_boundaries from skimage.data import camera from scipy.linalg import inv import matplotlib.pyplot as plt cv_ver = int(cv2.__version__.split('.')[0]) _cv2_LOAD_IMAGE_COLOR = cv2.IMREAD_COLOR if cv_ver >= 3 else cv2.CV_LOAD_IMAGE_COLOR class MR_saliency(object): """Python implementation of manifold ranking saliency""" weight_parameters = {'alpha':0.99, 'delta':0.1} superpixel_parameters = {'segs':200, 'compactness':10, 'max_iter':10, 'sigma':1, 'spacing':None, 'multichannel':True, 'convert2lab':None, 'enforce_connectivity':False, 'min_size_factor':0.5, 'max_size_factor':3, 'slic_zero':False} binary_thre = None def __init__(self, alpha = 0.99, delta = 0.1, segs = 200, compactness = 10, max_iter = 10, sigma = 1, spacing = None, multichannel = True, convert2lab = None, enforce_connectivity = False, min_size_factor = 0.5, max_size_factor = 3, slic_zero = False): self.weight_parameters['alpha'] = alpha self.weight_parameters['delta'] = delta self.superpixel_parameters['segs'] = segs self.superpixel_parameters['compactness'] = compactness self.superpixel_parameters['max_iter'] = max_iter self.superpixel_parameters['sigma'] = sigma self.superpixel_parameters['spacing'] = spacing self.superpixel_parameters['multichannel'] = multichannel self.superpixel_parameters['convert2lab'] = convert2lab self.superpixel_parameters['enforce_connectivity'] = enforce_connectivity self.superpixel_parameters['min_size_factor'] = min_size_factor self.superpixel_parameters['max_size_factor'] = max_size_factor self.superpixel_parameters['slic_zero'] = slic_zero def saliency(self,img): """ 主要的處理函數, 反映了算法的主要流程 """ # read image img = self.__MR_readimg(img) # superpixel # labels獲得的是什麼: 對於各個像素的超像素劃分的標記 labels = self.__MR_superpixel(img) # affinity matrix aff = self.__MR_affinity_matrix(img,labels) # first round first_sal = self.__MR_first_stage_saliency(aff,labels) # second round fin_sal = self.__MR_final_saliency(first_sal, labels,aff) return self.__MR_fill_superpixel_with_saliency(labels,fin_sal) def __MR_superpixel(self,img): """ 超像素劃分 """ return slic(img, self.superpixel_parameters['segs'], self.superpixel_parameters['compactness'], self.superpixel_parameters['max_iter'], self.superpixel_parameters['sigma'], self.superpixel_parameters['spacing'], self.superpixel_parameters['multichannel'], self.superpixel_parameters['convert2lab'], self.superpixel_parameters['enforce_connectivity'], self.superpixel_parameters['min_size_factor'], self.superpixel_parameters['max_size_factor'], self.superpixel_parameters['slic_zero']) def __MR_superpixel_mean_vector(self,img,labels): """ 返回關於關於每一個超像素的三個顏色通道的均值. """ s = sp.amax(labels)+1 vec = sp.zeros((s,3)).astype(float) # 每一個超像素的獲得的顏色均值是三個值, 三個通道各自一個均值. for i in range(s): mask = labels == i # img[mask]表示圖像上被標記爲同一個超像素的像素值 super_v = img[mask].astype(float) mean = sp.mean(super_v,0) vec[i] = mean return vec def __MR_affinity_matrix(self,img,labels): """ 得到關聯矩陣A """ W,D = self.__MR_W_D_matrix(img,labels) # 得到矩陣A aff = inv(D-self.weight_parameters['alpha']*W) aff[sp.eye(sp.amax(labels)+1).astype(bool)] = 0.0 # diagonal elements to 0 return aff def __MR_saliency(self,aff,indictor): """ 計算A*y """ return sp.dot(aff,indictor) def __MR_W_D_matrix(self,img,labels): """ 得到矩陣W和D """ s = sp.amax(labels)+1 vect = self.__MR_superpixel_mean_vector(img,labels) # 獲取超像素之間的鄰接矩陣, 這裏鄰接關係對應着False adj = self.__MR_get_adj_loop(labels) W = sp.spatial.distance.squareform(sp.spatial.distance.pdist(vect)) W = sp.exp(-1*W / self.weight_parameters['delta']) # 歸屬於不一樣超像素的像素之間, 不相鄰的賦予0 W[adj.astype(np.bool)] = 0 D = sp.zeros((s,s)).astype(float) for i in range(s): D[i, i] = sp.sum(W[i]) return W,D def __MR_boundary_indictor(self,labels): """ 這裏將四個邊界像素所在超像素指示值都設定爲0 """ s = sp.amax(labels)+1 up_indictor = (sp.ones((s,1))).astype(float) right_indictor = (sp.ones((s,1))).astype(float) low_indictor = (sp.ones((s,1))).astype(float) left_indictor = (sp.ones((s,1))).astype(float) upper_ids = sp.unique(labels[0,:]).astype(int) right_ids = sp.unique(labels[:,labels.shape[1]-1]).astype(int) low_ids = sp.unique(labels[labels.shape[0]-1,:]).astype(int) left_ids = sp.unique(labels[:,0]).astype(int) up_indictor[upper_ids] = 0.0 right_indictor[right_ids] = 0.0 low_indictor[low_ids] = 0.0 left_indictor[left_ids] = 0.0 return up_indictor,right_indictor,low_indictor,left_indictor def __MR_get_adj_loop(self, labels): """ 獲取超像素的鄰接矩陣 """ # 總的超像素數量, amax方法會返回最大的類別值 s = sp.amax(labels) + 1 # 超像素鄰接矩陣預約義 adj = np.ones((s, s), np.bool) # 對圖像的各個像素的超像素標記進行遍歷 for i in range(labels.shape[0] - 1): for j in range(labels.shape[1] - 1): # 下面的四個判斷, 檢查了以(i,j)爲左上角的一個2x2像素區域四個像素之間的連通關係 if labels[i, j] != labels[i+1, j]: # (i,j)與(i+1,j)不位於同一個超像素中, 就在超像素鄰接矩陣中對應位置置爲False # 注意, 有兩個位置, 由於鄰接矩陣能夠表示有向圖. adj[labels[i, j] , labels[i+1, j]] = False adj[labels[i+1, j], labels[i, j]] = False if labels[i, j] != labels[i, j + 1]: # (i,j)與(i,j+1) adj[labels[i, j] , labels[i, j+1]] = False adj[labels[i, j+1], labels[i, j]] = False if labels[i, j] != labels[i + 1, j + 1]: # (i,j)與(i+1,j+1) adj[labels[i, j] , labels[i+1, j+1]] = False adj[labels[i+1, j+1], labels[i, j]] = False if labels[i + 1, j] != labels[i, j + 1]: # (i+1,j)與(i,j+1) adj[labels[i+1, j], labels[i, j+1]] = False adj[labels[i, j+1], labels[i+1, j]] = False # 這裏循環結束後, 獲得的adj中的True表示的是圖像像素的超像素標記並非相鄰的.(這兩個超像素的 # 像素之間並不相鄰), 而對應的False表示的是超像素的元素之間是相鄰的. # 這裏肯定了四個邊上的像素對應的超像素標記, 這裏會查找特定向量的惟一超像素標記的集合 upper_ids = sp.unique(labels[0,:]).astype(int) right_ids = sp.unique(labels[:,labels.shape[1]-1]).astype(int) low_ids = sp.unique(labels[labels.shape[0]-1,:]).astype(int) left_ids = sp.unique(labels[:,0]).astype(int) # np.append會拼接指定的向量. 四個邊拼接起來, 獲得的bd表示被認爲是背景的超像素標記 bd = np.append(upper_ids, right_ids) bd = np.append(bd, low_ids) bd = sp.unique(np.append(bd, left_ids)) for i in range(len(bd)): for j in range(i + 1, len(bd)): # 任意兩個包含邊界像素的超像素, 對應的鄰接關係也被設置爲False adj[bd[i], bd[j]] = False adj[bd[j], bd[i]] = False # 這裏的循環結束後, adj表示的是全部包含邊界像素的超像素之間都認爲是元素相鄰的, 這裏設定爲False return adj def __MR_fill_superpixel_with_saliency(self,labels,saliency_score): """ 爲各個超像素區域賦予對應的顯著性得分 """ sa_img = labels.copy().astype(float) for i in range(sp.amax(labels)+1): mask = labels == i sa_img[mask] = saliency_score[i] return cv2.normalize(sa_img,None,0,255,cv2.NORM_MINMAX) def __MR_first_stage_saliency(self,aff,labels): """ 獲取邊界查詢(種子)對應的圖得分. """ # 邊界指示對應爲0 up,right,low,left = self.__MR_boundary_indictor(labels) # 計算的是節點到非邊界元素的相關性的補數, 也就是非顯著性圖 up_sal = 1-self.__MR_saliency(aff,up) # sp.dot(aff, up) up_img = self.__MR_fill_superpixel_with_saliency(labels,up_sal) right_sal = 1-self.__MR_saliency(aff,right) right_img = self.__MR_fill_superpixel_with_saliency(labels,right_sal) low_sal = 1-self.__MR_saliency(aff,low) low_img = self.__MR_fill_superpixel_with_saliency(labels,low_sal) left_sal = 1-self.__MR_saliency(aff,left) left_img = self.__MR_fill_superpixel_with_saliency(labels,left_sal) # 使用非顯著性圖乘積的補數來做爲顯著性圖 return 1-up_img*right_img*low_img*left_img def __MR_second_stage_indictor(self,saliency_img_mask,labels): s = sp.amax(labels)+1 # get ids from labels image ids = sp.unique(labels[saliency_img_mask]).astype(int) # indictor indictor = sp.zeros((s,1)).astype(float) indictor[ids] = 1.0 return indictor def __MR_final_saliency(self,integrated_sal, labels, aff): # get binary image if self.binary_thre == None: thre = sp.median(integrated_sal.astype(float)) mask = integrated_sal > thre # get indicator ind = self.__MR_second_stage_indictor(mask,labels) return self.__MR_saliency(aff,ind) # read image def __MR_readimg(self,img): if isinstance(img,str): # a image path img = cv2.imread(img, _cv2_LOAD_IMAGE_COLOR) img = cv2.cvtColor(img,cv2.COLOR_RGB2LAB).astype(float)/255 h = 100 w = int(float(h)/float(img.shape[0])*float(img.shape[1])) return cv2.resize(img,(w,h))