1. 程式人生 > >OpenCV實現二值影象細化的演算法

OpenCV實現二值影象細化的演算法

        細化演算法通常和骨骼化、骨架化演算法是相同的意思,也就是thin演算法或者skeleton演算法。雖然很多影象處理的教材上不是這麼寫的,具體原因可以看這篇論文,Louisa Lam, Seong-Whan Lee, Ching Y. Suen,“Thinning Methodologies-A Comprehensive Survey ”,IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINEINTELLIGENCE, VOL. 14, NO. 9, SEPTEMBER 1992 ,總結了幾乎所有92年以前的經典細化演算法。

函式:void cvThin( IplImage* src, IplImage* dst, int iterations=1)
功能:將IPL_DEPTH_8U型二值影象進行細化
引數:src,原始IPL_DEPTH_8U型二值影象
          dst,目標儲存空間,必須事先分配好,且和原影象大小型別一致
          iterations,迭代次數
參考文獻:T. Y. Zhang and C. Y. Suen, “A fast parallel algorithm for thinning digital patterns,” Comm. ACM, vol. 27, no. 3, pp. 236-239, 1984. 

void cvThin( IplImage* src, IplImage* dst, int iterations=1)
{
 CvSize size = cvGetSize(src);

 cvCopy(src, dst);
    int n = 0,i = 0,j = 0;
 for(n=0; n<iterations; n++)
 {
  IplImage* t_image = cvCloneImage(dst);
  for(i=0; i<size.height;  i++)
  {
   for(j=0; j<size.width; j++)
   {
    if(CV_IMAGE_ELEM(t_image,byte,i,j)==1)
    {
     int ap=0;
     int p2 = (i==0)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j);
     int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j+1);
     if (p2==0 && p3==1)
     {
      ap++;
     }
     int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i,j+1);
     if(p3==0 && p4==1)
     {
      ap++;
     }
     int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j+1);
     if(p4==0 && p5==1)
     {
      ap++;
     }
     int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j);
     if(p5==0 && p6==1)
     {
      ap++;
     }
     int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j-1);
     if(p6==0 && p7==1)
     {
      ap++;
     }
     int p8 = (j==0)?0:CV_IMAGE_ELEM(t_image,byte,i,j-1);
     if(p7==0 && p8==1)
     {
      ap++;
     }
     int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i-1,j-1);
     if(p8==0 && p9==1)
     {
      ap++;
     }
     if(p9==0 && p2==1)
     {
      ap++;
     }
     if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7)
     {
      if(ap==1)
      {
       if(!(p2 && p4 && p6))
       {
        if(!(p4 && p6 && p8)) 
        {
         CV_IMAGE_ELEM(dst,byte,i,j)=0;
        }
       }
      }
     }
    }
   }
  }
  cvReleaseImage(&t_image);
  t_image = cvCloneImage(dst);
  for(i=0; i<size.height;  i++)
  {
   for(int j=0; j<size.width; j++)
   {
    if(CV_IMAGE_ELEM(t_image,byte,i,j)==1)
    {
     int ap=0;
     int p2 = (i==0)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j);
     int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j+1);
     if (p2==0 && p3==1)
     {
      ap++;
     }
     int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i,j+1);
     if(p3==0 && p4==1)
     {
      ap++;
     }
     int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j+1);
     if(p4==0 && p5==1)
     {
      ap++;
     }
     int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j);
     if(p5==0 && p6==1)
     {
      ap++;
     }
     int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j-1);
     if(p6==0 && p7==1)
     {
      ap++;
     }
     int p8 = (j==0)?0:CV_IMAGE_ELEM(t_image,byte,i,j-1);
     if(p7==0 && p8==1)
     {
      ap++;
     }
     int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i-1,j-1);
     if(p8==0 && p9==1)
     {
      ap++;
     }
     if(p9==0 && p2==1)
     {
      ap++;
     }
     if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7)
     {
      if(ap==1)
      {
       if(p2*p4*p8==0)
       {
        if(p2*p6*p8==0)
        {
         CV_IMAGE_ELEM(dst, byte,i,j)=0;
        }
       }
      }
     }                    
    }
   }
  }            
  cvReleaseImage(&t_image);
 }
}
//使用舉例
#include "cxcore.h"
#include "cv.h"
#include "highgui.h"

 

int main(int argc, char* argv[])
{
 if(argc!=2)
 {
  return 0;
 }
 IplImage *pSrc = NULL,*pDst = NULL,*pTmp = NULL;

//傳入一個灰度影象
 pSrc = cvLoadImage(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
 if(!pSrc)
 {
  return 0;
 }
 pTmp = cvCloneImage(pSrc);
    pDst = cvCreateImage(cvGetSize(pSrc),pSrc->depth,pSrc->nChannels);
 cvZero(pDst);
 cvThreshold(pSrc,pTmp,128,1,CV_THRESH_BINARY_INV);//做二值處理,將影象轉換成0,1格式
 //cvSaveImage("c://Threshold.bmp",pTmp,0);
 cvThin(pTmp,pDst,8);//細化,通過修改iterations引數進一步細化
 cvNamedWindow("src",1);
 cvNamedWindow("dst",1);
 cvShowImage("src",pSrc);
 //將二值影象轉換成灰度,以便顯示
 int i = 0,j = 0;
 CvSize size = cvGetSize(pDst);
 for(i=0; i<size.height;  i++)
 {
  for(j=0; j<size.width; j++)
  {
   if(CV_IMAGE_ELEM(pDst,uchar,i,j)==1)
   {
    CV_IMAGE_ELEM(pDst,uchar,i,j) = 0;
   }
   else
   {
    CV_IMAGE_ELEM(pDst,uchar,i,j) = 255;
   }
  }
 }
 //cvSaveImage("c://thin.bmp",pDst);
 cvShowImage("dst",pDst);
 cvWaitKey(0);
    cvReleaseImage(&pSrc);
 cvReleaseImage(&pDst);
 cvReleaseImage(&pTmp);
 cvDestroyWindow("src");
 cvDestroyWindow("dst");
 return 0;
} 

相關推薦

OpenCV實現影象細化演算法

        細化演算法通常和骨骼化、骨架化演算法是相同的意思,也就是thin演算法或者skeleton演算法。雖然很多影象處理的教材上不是這麼寫的,具體原因可以看這篇論文,Louisa Lam, Seong-Whan Lee, Ching Y. Suen,“Thinni

opencv實現影象細化

opencv實現二值影象細化的演算法 細化演算法通常和骨骼化、骨架化演算法是相同的意思,也就是thin演算法或者skeleton演算法。雖然很多影象處理的教材上不是這麼寫的,具體原因可以看這篇論文,Louisa Lam, Seong-Whan Lee, Chin

利用PIL.ImageOps.invert實現影象黑白反轉

利用PIL.ImageOps.invert實現二值影象黑白反轉   import PIL.ImageOps from PIL import Image img = Image.open('D:\\Desktop\\計算機視覺\\image\\0.png') img =

利用opencv逼近影象的邊界點,並過濾不需要的邊界,達到尋邊效果。(轉載請說明出處)

二值化影象; 利用黑白畫素值求差,得到邊緣點; 過濾邊緣點找到合適區域; 利用cvFitLine2D擬合線。 做的比較粗糙,搜尋時間在10ms左右,希望有研究opencv的朋友斧正。 效果預覽: 、 void CvProcess::FindLine( Ip

實現影象連通區標記之區域生長法

連通區標記是最基本的影象處理演算法之一。該演算法中,按從左至右、從上至下的順序,對整幅影象進行掃描,通過比較每個前景畫素的鄰域進行連通區標記,並建立等效標記列表。最後,合併等效標記列表,並再次掃描影象以更新標記。演算法的優點的是通俗易懂,缺點是需要兩次掃描影象,效率不高。區域

實現基於C語言的影象連通域標記演算法

實現基於C語言的二值影象連通域標記演算法 1 #include <stdio.h> 2 #include <stdarg.h> 3 #include <stddef.h> 4 #include <stdlib.h> 5 #includ

opencv 簡單的實現

//灰度圖二值化 傳入的影象 閾值 void erzhi(Mat &img,uchar gray) { //行列 int row = img.rows; int col = img.cols; //遍歷影象 int i,j; uchar *p; for( i =

otsu結合OpenCV實現灰度影象自動閾處理

   簡單的說,這種演算法假設一副影象由前景色和背景色組成,通過統計學的方法來選取一個閾值,使得這個閾值可以將前景色和背景色儘可能的分開。 或者更準確的說是在某種判據下最優。與數理統計領域的 fisher 線性判別演算法其實是等價的。 otsu演算法中這個判據就是最大類間方差

SSE影象演算法優化系列十五:二值影象的Euclidean distance map(EDM)特徵圖計算及其優化。 SSE影象演算法優化系列九:靈活運用SIMD指令16倍提升Sobel邊緣檢測的速度(4000*3000的24點陣圖像時間由480ms降低到30ms)

  Euclidean distance map(EDM)這個概念可能聽過的人也很少,其主要是用在二值影象中,作為一個很有效的中間處理手段存在。一般的處理都是將灰度圖處理成二值圖或者一個二值圖處理成另外一個二值圖,而EDM演算法確是由一幅二值圖生成一幅灰度圖。其核心定義如下:   The definitio

邏輯迴歸和樸素貝葉斯演算法實現分類(matlab程式碼)

資料簡介:共有306組資料,每組資料有三個屬性(x1,x2,x2),屬於0類或者1類。 資料序號末尾為1的是測試集,有31組;其他的作為訓練集,有275組。 clear clc load('

OpenCV-影象連通域分析

通域分析對於影象處理後面涉及到模式識別的內容來說是基礎 連通區域(Connected Component)一般是指影象中具有相同畫素值且位置相鄰的前景畫素點組成的影象區域(Region,Blob)。連通區域分析(Connected Component Analysis,C

OpenCV學習筆記之針對影象的邊緣光滑處理(突出部消除)

處理程式碼分為兩部分,第一部分用於去除邊緣的突出部,第二部分用於邊緣光滑。具體如下所示 1.去除邊緣突出部 //去除二值影象邊緣的突出部 //uthreshold、vthreshold分別表示突出部的寬度閾值和高度閾值 //type代表突出部的顏色,0表示黑色,1代表白色

Qt實現細胞影象區域上色

問題描述 在細胞影象處理和識別中,區域特徵是非常重要的,也是分析細胞特徵的前提和基礎。這些區域特徵可以是外接矩形、畫素點個數等。因此,我們需要得到跟蹤得到不同區域,才能對其進行特徵分析。針對該問題,我們需要設計一個類和相關方法,用於跟蹤得到每個區域,並填上不同

opencv 刪除影象中面積較小的連通域

對於上圖的二值化影象,要去除左下角和右上角的噪點,方法:使用opencv去掉黑色面積較小的連通域。程式碼 CvSeq* contour = NULL; double minarea = 100.0; double tmparea = 0.0;

Win8 Metro(C#)數字影象處理--2.40影象輪廓提取演算法

 [函式名稱] 二值影象輪廓提取 ContourExtraction(WriteableBitmap src) [演算法說明]   二值影象的輪廓提取對於影象識別,影象分割有著重要意義。該演算法的核心就是將影象目標的內部點消除。所謂內部點,我們要根據當前畫素點的鄰域來進

影象連通域標記演算法優化

文章概要     非常感謝☆Ronny丶博主在其博文《影象分析:二值影象連通域標記》中對二值影象連通域的介紹和演算法闡述,讓我這個毫無資料結構演算法底子的小白能夠理解和復現程式碼。本文的目的是基於我自己的理解,對該博文中Two-Pass演算法的一些優化和補充,同時也希望幫助更多像我一樣的人較快地掌握

Ubuntu 14.04 下使用 OpenCV 圖片化處理

ubuntu14 install article all tail .net .com enc -o 參考: OpenCV - Ubuntu 14.04 64 bit 圖片二值化工具 Ubuntu 14.04 下使用 OpenCV 圖片二值化處理 TBD。Ubuntu

基於卷積神經網路特徵圖的影象分割

       目標檢測是當前大火的一個研究方向,FasterRCNN、Yolov3等一系列結構也都在多目標檢測的各種應用場景或者競賽中取得了很不錯的成績。但是想象一下,假設我們需要通過影象檢測某個產品上是否存在缺陷,或者通過衛星圖判斷某片海域是否有某公司的船隻

影象分析:影象連通域標記

一、前言 二值影象,顧名思義就是影象的亮度值只有兩個狀態:黑(0)和白(255)。二值影象在影象分析與識別中有著舉足輕重的地位,因為其模式簡單,對畫素在空間上的關係有著極強的表現力。在實際應用中,很多影象的分析最終都轉換為二值影象的分析,比如:醫學影象分析、前景檢測、字元識

影象的腐蝕膨脹原理(附程式碼)

程式碼: #include <iostream> #include<vector> #include<iomanip> using namespace std; #define picX 6 #define picY 6 type