Android OpenCV(二)主體識別 位置檢測

前言

??工作中遇到需要通過OpenCV找到圖片主體體積占圖片百分比的比例,這里做一個問題解決思路的記錄遍坟。該方面新手小白拳亿,有不對的地方可以評論指出哈 。

重要API

Sobel算法

Sobel 計算參考文章

索貝爾算子是計算機視覺領(lǐng)域的一種重要處理方法愿伴。
主要用于獲得數(shù)字圖像的一階梯度肺魁,常見的應(yīng)用和物理意義是邊緣檢測。
索貝爾算子是把圖像中每個像素的上下左右四領(lǐng)域的灰度值加權(quán)差隔节,在邊緣處達到極值從而檢測邊緣鹅经。在技術(shù)上,它是一離散性差分算子怎诫,用來運算圖像亮度函數(shù)的梯度之近似值瘾晃。在圖像的任何一點使用此算子,將會產(chǎn)生對應(yīng)的梯度矢量或是其法矢量幻妓。索貝爾算子不但產(chǎn)生較好的檢測效果蹦误,而且對噪聲具有平滑抑制作用,但是得到的邊緣較粗肉津,且可能出現(xiàn)偽邊緣强胰。
該算子包含兩組3x3的矩陣,分別為橫向及縱向妹沙,將之與圖像作平面卷積偶洋,即可分別得出橫向及縱向的亮度差分近似值。如果以A代表原始圖像距糖,Gx及Gy分別代表經(jīng)橫向及縱向邊緣檢測的圖像玄窝,其公式如下:


image.png

圖像的每一個像素的橫向及縱向梯度近似值可用以下的公式結(jié)合,來計算梯度的大小肾筐。
image.png

然后可用以下公式計算梯度方向哆料。
image.png

在以上例子中,如果以上的角度θ等于零吗铐,即代表圖像該處擁有縱向邊緣,左方較右方暗 【引用:百度百科】
//src : 輸入圖像  dst: 輸出圖像
//ddepth: 輸出圖像的深度(可以理解為數(shù)據(jù)類型)杏节,-1表示與原圖像相同的深度
//dx:  dy: 當組合為dx=1,dy=0時求x方向的一階導(dǎo)數(shù)唬渗,當組合為dx=0,dy=1時求y方向的一階導(dǎo)數(shù)
//ksize: (可選參數(shù))Sobel算子的大小典阵,必須是1,3,5或者7,默認為3。
//scale: 對導(dǎo)數(shù)計算結(jié)果進行縮放的縮放因子镊逝,默認系數(shù)為1壮啊,不進行縮放
//delta: 偏值,在計算結(jié)果中加上偏值撑蒜。
//borderType: 像素外推法選擇標志歹啼。默認參數(shù)為BORDER_DEFAULT,表示不包含邊界值倒序填充座菠。
public static void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType) 
  • 注意點
  1. 圖像深度是指存儲每個像素值所用的位數(shù)狸眼,例如cv2.CV_8U,指的是8位無符號數(shù)浴滴,取值范圍為0~255拓萌,超出范圍則會被截斷(截斷指的是,當數(shù)值大于255保留為255升略,當數(shù)值小于0保留為0微王,其余不變)。
    ??具體還有:CV_16S(16位無符號數(shù))品嚣,CV_16U(16位有符號數(shù))炕倘,CV_32F(32位浮點數(shù)),CV_64F(64位浮點數(shù))
    ??當ddepth 輸出圖像深度采用CV_8U翰撑,由于Sobel算子在計算X方向梯度時激才,如果某像素點右側(cè)像素值大于左側(cè)像素值,則梯度大小為正保留额嘿,相反梯度大小為負被截斷瘸恼,梯度大小保存為0。這里可以使用 CV_32F 防止數(shù)據(jù)存在負數(shù)情況册养。

  2. 在我們使用CV_32F數(shù)據(jù)類型求出XY階后东帅,需要配合使用函數(shù)convertScaleAbs()將圖像深度為CV_64F的梯度圖像重新轉(zhuǎn)化為CV_8U,這是由于函數(shù)cv2.imshow()的默認顯示為8位無符號數(shù),即[0,255]球拦。

具體思路

??第一步靠闭,使用OpenCV的 Sobel算子來計算x,y方向上的梯度坎炼,在x方向上減去y方向上的梯度愧膀,通過這個減法,我們會留下有高水平梯度和低垂直梯度的圖像區(qū)域谣光。

        Mat gradX = new Mat();
        Mat gradY = new Mat();
        Mat binary = new Mat();
        //求X Y 階 轉(zhuǎn)換為32位浮點數(shù)個數(shù)
        Imgproc.Sobel(grayImage, gradX, CvType.CV_32F, 1, 0, -1);
        Imgproc.Sobel(grayImage, gradY, CvType.CV_32F, 0, 1, -1);
        //相減
        Core.subtract(gradX, gradY, binary);
        //轉(zhuǎn)換數(shù)據(jù)格式CV_8U
        Core.convertScaleAbs(binary, binary);

以上步驟我們可以得到一個帶有很多噪點的邊界圖檩淋,為了剔除掉那些噪點對于主體的判斷,我們需要使用 blur 方法 和黑白兩極化對圖片進行處理

??第二步萄金,使用低通濾潑器平滑圖像(9 x 9內(nèi)核),這將有助于平滑圖像中的高頻噪聲蟀悦。低通濾波器的目標是降低圖像的變化率媚朦。如將每個像素替換為該像素周圍像素的均值。這樣就可以平滑并替代那些強度變化明顯的區(qū)域日戈。

//去噪
Imgproc.blur(binary, binary, new Size(9.0, 9.0));
//對模糊圖像二值化询张。梯度圖像中不大于90的任何像素都設(shè)置為0(黑色)。 否則浙炼,像素設(shè)置為255(白色)為第五步做準備工作
Imgproc.threshold(binary, binary, 90.0, 255.0, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);

??第三步份氧,通過上述方法可以得到一個黑白圖,但是圖片中可能會存在很多空白空隙弯屈, 我們要用白色填充這些空余蜗帜,使得后面的程序更容易識別昆蟲區(qū)域,這需要做一些形態(tài)學(xué)方面的操作季俩。

//為形態(tài)學(xué)操作返回指定大小和形狀的結(jié)構(gòu)元素 用于形態(tài)學(xué)處理
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(25.0, 25.0));
// 使用腐蝕和膨脹作為基本操作來執(zhí)行高級形態(tài)學(xué)轉(zhuǎn)換
Imgproc.morphologyEx(binary,binary,Imgproc.MORPH_CLOSE,kernel);

??第四步钮糖, 通過上述處理,可能還會存在一些 大的噪點酌住, 可以通過形態(tài)學(xué)腐化和膨脹進行消除

Point p = new Point(-1.0, -1.0);
Imgproc.erode(binary, binary, ker, p, 4);
Imgproc.dilate(binary, binary, ker, p, 4);

??第五步店归,通過 findContours()函數(shù)框選出主體的位置信息

List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
// binary : 要檢索的圖片,必須是為二值圖酪我,即黑白的
//hierarchy : 結(jié)果返回值
Imgproc.findContours(binary,contours,hierarchy,
                Imgproc.RETR_EXTERNAL,Imgproc.CHAIN_APPROX_SIMPLE);

findContours 函數(shù) 最后兩個參數(shù)消痛,mode 和 method 單獨拿出來列舉下 不同的參數(shù)代表的含義
mode
Imgproc.RETR_EXTERNAL 表示只檢測外輪廓
Imgproc.RETR_LIST 檢測的輪廓不建立等級關(guān)系
Imgproc.RETR_CCOMP 建立兩個等級的輪廓,上面的一層為外邊界都哭,里面的一層為內(nèi)孔的邊界信息秩伞。如果內(nèi)孔內(nèi)還有一個連通物體,這個物體的邊界也在頂層欺矫。
Imgproc.RETR_TREE 建立一個等級樹結(jié)構(gòu)的輪廓纱新。

method
Imgproc.CHAIN_APPROX_NONE 存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1穆趴,即max(abs(x1-x2)脸爱,abs(y2-y1))==1
Imgproc.CHAIN_APPROX_SIMPLE 壓縮水平方向,垂直方向未妹,對角線方向的元素簿废,只保留該方向的終點坐標,例如一個矩形輪廓只需4個點來保存輪廓信息

??結(jié)果都存儲在 contours 數(shù)組中络它,我們可以使用他進行一些業(yè)務(wù)判斷族檬。
??由于脫敏原因,這里沒有demo圖片化戳,該篇文章 主要參考文章對我的幫助非常大单料,小白這里只是做一個開發(fā)記錄,今天的這篇文章就到這里。

參考文章

識別顏色方塊并提取輪廓

OpenCV自動檢測圖像中的物體并裁剪

Sobel()計算圖像梯度的細節(jié)講解

OpenCV API官網(wǎng)地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末看尼,一起剝皮案震驚了整個濱河市递鹉,隨后出現(xiàn)的幾起案子盟步,更是在濱河造成了極大的恐慌藏斩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件却盘,死亡現(xiàn)場離奇詭異狰域,居然都是意外死亡,警方通過查閱死者的電腦和手機黄橘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門兆览,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人塞关,你說我怎么就攤上這事抬探。” “怎么了帆赢?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵小压,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么脐瑰? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任步悠,我火速辦了婚禮,結(jié)果婚禮上缨称,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好抢呆,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著笛谦,像睡著了一般抱虐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上揪罕,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天梯码,我揣著相機與錄音,去河邊找鬼好啰。 笑死轩娶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的框往。 我是一名探鬼主播鳄抒,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了许溅?” 一聲冷哼從身側(cè)響起瓤鼻,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贤重,沒想到半個月后茬祷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡并蝗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年祭犯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滚停。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡沃粗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出键畴,到底是詐尸還是另有隱情最盅,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布起惕,位于F島的核電站涡贱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏疤祭。R本人自食惡果不足惜盼产,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勺馆。 院中可真熱鬧戏售,春花似錦、人聲如沸草穆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悲柱。三九已至锋喜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豌鸡,已是汗流浹背嘿般。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涯冠,地道東北人炉奴。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像蛇更,于是被迫代替她去往敵國和親瞻赶。 傳聞我的和親對象是個殘疾皇子赛糟,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容