OPENCV形態學算法-2

一.漫水填充算法算法

         該算法經過一個指定的種子點,來分析整張圖片上的像素,並設置像素差別閾值,在閾值類的點,最後變成相同的顏色.該方法經過上下限和連通方式來達到不一樣的連通效果.編程

         該方法經常使用與標記和分離圖像的一部分,以便於對其作進一步的分析和處理,填充的結果老是連通的區域.函數

         API:void floodFill(源圖像,掩碼,Point 種子點,scaral 染色值,Rect* 重繪區域的最小邊界矩形區域,scaral 與種子點顏色的負差最大值,scaral 與種子點顏色的正差最大值,int 操做方式);spa

         注:1掩碼的大小和源圖像相同,掩碼中不爲0的區域,對應的原圖中座標的像素,在處理的時候將被忽略.code

                  2.最小矩形是一個可選參數,默認爲0blog

                  3.操做方式的第八位爲4,則連通時只會向水平垂直方向蔓延,爲8,還包括對角線蔓延,高八位爲FLOOD_FIXED_RANGE時,上下限是和種子點顏色相比,不然,是當前像素和相鄰像素差圖片

實際使用代碼以下it

Mat srcImage;
Mat dstImage;
Point mousePoint;
const int g_newValueMax = 255;
int g_newValue;
const int g_lodiffMax = 255;
int g_lodiffValue;
const int g_updiffMax = 255;
int g_updiffValue;

void onMouseEvent(int eventID,int x,int y,int flag,void* userData);
void onTrackBarNewValue(int pos,void* userData);
void onTrackBarLoDiffValue(int pos,void* userData);
void onTrackBarUpDiffValue(int pos,void* userData);


int main(void)
{
   srcImage = imread("F:\\opencv\\OpenCVImage\\floodFill.jpg");
   namedWindow("floodfill image");
   namedWindow("src image");
   
   mousePoint = Point(-1,-1);
   g_newValue = 100;
   g_lodiffValue = 25;
   g_updiffValue = 25;
   setMouseCallback("src image", onMouseEvent);
   createTrackbar("new value", "src image", &g_newValue, g_newValueMax,onTrackBarNewValue);
   createTrackbar("updiff value", "src image", &g_updiffValue, g_updiffMax,onTrackBarUpDiffValue);
   createTrackbar("lodiff value", "src image", &g_lodiffValue, g_lodiffMax,onTrackBarLoDiffValue);
   onTrackBarLoDiffValue(g_lodiffValue, 0);
   
   
   imshow("src image", srcImage);
   
   moveWindow("src image", 0, 0);
   moveWindow("floodfill image", srcImage.cols, 0);
   
   waitKey(0);
   return 0;
}

void onMouseEvent(int eventID,int x,int y,int flag,void* userData)
{
   if(eventID == EVENT_LBUTTONDOWN)
   {
       mousePoint = Point(x,y);
       onTrackBarNewValue(g_newValue, 0);
   }
}

void onTrackBarNewValue(int pos,void* userData)
{
   if(mousePoint.x >= 0 && mousePoint.y >=0)
   {
       Rect rect;
       Mat tempImage;
       tempImage = srcImage.clone();
       floodFill(srcImage, mousePoint, Scalar(g_newValue,g_newValue,g_newValue),&rect,Scalar(g_lodiffValue,g_lodiffValue,g_lodiffValue),Scalar(g_updiffValue,g_updiffValue,g_updiffValue),4|FLOODFILL_FIXED_RANGE);
       dstImage = srcImage.clone();
       srcImage = tempImage.clone();
       imshow("floodfill image", dstImage);
   }
   else
   {
       dstImage = srcImage.clone();
       imshow("floodfill image", dstImage);
   }
}
void onTrackBarLoDiffValue(int pos,void* userData)
{
   if(mousePoint.x >= 0 && mousePoint.y >=0)
   {
       Rect rect;
       Mat tempImage;
       tempImage = srcImage.clone();
       floodFill(srcImage, mousePoint, Scalar(g_newValue,g_newValue,g_newValue),&rect,Scalar(g_lodiffValue,g_lodiffValue,g_lodiffValue),Scalar(g_updiffValue,g_updiffValue,g_updiffValue),8|FLOODFILL_FIXED_RANGE);
       dstImage = srcImage.clone();
       srcImage = tempImage.clone();
       imshow("floodfill image", dstImage);
   }
   else
   {
       dstImage = srcImage.clone();
       imshow("floodfill image", dstImage);
   }
}
void onTrackBarUpDiffValue(int pos,void* userData)
{
   if(mousePoint.x >= 0 && mousePoint.y >=0)
   {
       Rect rect;
       Mat tempImage;
       tempImage = srcImage.clone();
       floodFill(srcImage, mousePoint, Scalar(g_newValue,g_newValue,g_newValue),&rect,Scalar(g_lodiffValue,g_lodiffValue,g_lodiffValue),Scalar(g_updiffValue,g_updiffValue,g_updiffValue),8|FLOODFILL_FIXED_RANGE);
       dstImage = srcImage.clone();
       srcImage = tempImage.clone();
       imshow("floodfill image", dstImage);
   }
   else
   {
       dstImage = srcImage.clone();
       imshow("floodfill image", dstImage);
   }
}

二.圖像金字塔opencv

         圖像金字塔是一種對圖像進行向上採樣或者向下採樣的算法,所謂向上向下採樣,實際上就是放大圖像縮小圖像.event

         圖像金字塔分爲高斯金字塔和拉普拉斯金字塔,高斯金字塔向下採樣,下降分辨力,拉普拉斯金字塔配合高斯金字塔,向上還原源圖像

         下一層圖像的面積是源圖像面積的1/4,採樣函數分別爲pyrUp和pyrDown兩個函數並非互逆的,pyrDown是一個會丟失信息的函數.

         API:void pyrUp(源圖,目的圖,Size 放大係數,int 邊緣類型)

         注:向上採樣並放大圖像,目的圖和源圖的通道,深度一致,放大係數有默認值,源圖長*2 寬*2

         API:void pyrDown(源圖,目的圖,Size 放大係數,int 邊緣類型)

         注:向下採樣並模糊一張圖片,圖片尺寸有默認值 源圖長/2 源圖寬/2,總體是源圖的四分之一.

使用例程以下

Mat srcImage;
//圖像放大
Mat pyrupImage;
Mat pyrupShowImage;
const int g_pyrupMax = 10;
int g_pyrupCount;
void onTrackBarPyrup(int pos,void* userData);

//圖像縮小
Mat pyrdownImage;
Mat pyrdownShowImage;
const int g_pyrdownMax = 10;
int g_pyrdownCount;
void onTrackBarPyrdown(int pos,void* userData);

int main(int argc,char* argv[])
{
   srcImage = imread("F:\\opencv\\OpenCVImage\\pyr.jpg");
   if(srcImage.empty())
   {
       return -1;
   }
   namedWindow("src image");
   namedWindow("pyrup image");
   namedWindow("pyrdown image");
   
   g_pyrupCount = 1;
   createTrackbar("pyrup count", "pyrup image", &g_pyrupCount, g_pyrupMax,onTrackBarPyrup,0);
   onTrackBarPyrup(g_pyrupCount,0);
   
   g_pyrdownCount = 1;
   createTrackbar("pyrdown count", "pyrdown image", &g_pyrdownCount, g_pyrdownMax,onTrackBarPyrdown,0);
   onTrackBarPyrdown(g_pyrdownCount, 0);
   
   imshow("src image", srcImage);
   
   moveWindow("src image", 0, 0);
   moveWindow("pyrup image", srcImage.cols, 0);
   moveWindow("pyrdown image", srcImage.cols*2, 0);

   waitKey(0);
   return 0;
}
//圖像放大
void onTrackBarPyrup(int pos,void* userData)
{
   if(pos == 0)
   {
       imshow("pyrup image", srcImage);
   }
   else
   {
       Mat tempImage;
       tempImage = srcImage.clone();
       for(int i = 0; i < pos; i++)
       {
           pyrUp(tempImage, pyrupImage);
           tempImage = pyrupImage.clone();
       }
       if(pyrupImage.cols > srcImage.cols && pyrupImage.rows > srcImage.rows)
       {
           //pyrupShowImage = pyrupImage(Range(0,srcImage.rows),Range(0,srcImage.cols));
           imshow("pyrup image", pyrupImage);
       }
       else
       {
           imshow("pyrup image", pyrupImage);
       }
   }
}
//圖像縮小
 void onTrackBarPyrdown(int pos,void* userData)
 {
     if(pos == 0)
     {
         imshow("pyrdown image", srcImage);
     }
     else
     {
         Mat tempImage;
         tempImage = srcImage.clone();
         for(int i = 0; i < pos; i++)
         {
             pyrDown(tempImage, pyrdownImage);
             tempImage = pyrdownImage.clone();
         }
         if(pyrdownImage.cols > srcImage.cols && pyrdownImage.rows > srcImage.rows)
         {
             pyrdownShowImage = pyrdownImage(Range(0,srcImage.rows),Range(0,srcImage.cols));
             imshow("pyrdown image", pyrdownShowImage);
         }
         else
         {
             imshow("pyrdown image", pyrdownImage);
         }
     }
 }

三.圖像大小從新調整resize

         resize用於將源目標精確的轉換爲指定大小的目標圖像,在圖像放大縮小的時候頗有用

         API: void resize(源,目標,Size 目標尺寸,double x方向縮放係數,double y方向上縮放係數,int 差值方式)

         注:x方向縮放係數默認值0,函數自動根據源圖像大小和目標尺寸計算,y方向縮放係數也是同樣.插值方式決定了放大縮小之後的效果,主要有以下幾種插值方法 INTER_LINE 線性插值INTER_NEAREST 最近鄰插值  INNER_CUBIC 4*4區域內三次樣條插值INNER_AREA 區域插值INNER_LANCZOS4 8*8區域內鄰域插值.

         插值方式的選擇對於屢次resize有很大影響,例子以下

//圖像從新設置大小 resize
Mat srcImage;
const int g_resizeMax = 1000;
int g_resizeValue = 0;
Mat resizeImage;
void onTrackBarResize(int pos,void* userData);


int main(int argc,char* argv[])
{
   srcImage = imread("F:\\opencv\\OpenCVImage\\resize.jpg");
   
   namedWindow("src image");
   namedWindow("resize image");
   
   g_resizeValue = srcImage.rows;
   createTrackbar("size value", "resize image", &g_resizeValue, g_resizeMax,onTrackBarResize,0);
   onTrackBarResize(g_resizeValue, 0);
   
   imshow("src image", srcImage);
   
   moveWindow("src image", 0, 0);
   moveWindow("resize image", srcImage.cols, 0);
   
   waitKey(0);
   return 0;
}

void onTrackBarResize(int pos,void* userData)
{
   if(pos == 0)
   {
       imshow("resize image", srcImage);
   }
   else
   {
       //INTER_LINEAR INTER_CUBIC INTER_AREA INTER_NEAREST
       resize(srcImage, resizeImage, Size(g_resizeValue,g_resizeValue),0,0,INTER_NEAREST);
       imshow("resize image", resizeImage);
   }
}

四:圖像的閾值化

         圖像的閾值化是指經過一些算法和決策手段,將圖像中的像素編程兩種指定像素的集合,例如,將灰度圖轉換成徹底的黑白圖,或者直接提出低於或者高於必定值的像素.

         圖像的閾值化在某些場合下,對於圖像的邊緣提取十分有效果.

         API: void Threshold(源圖,目標圖,double 閾值,double 最大值,int 閾值類型)

         注:1.源和目標圖都必須是單通道灰度圖像

           2.閾值類型決定了閾值化之後,圖像中將僅存在哪兩種像素點

                  THRESH_BINARY 低於閾值爲0 高於閾值爲給定最大值

                  THRESH_BINARY_INV 低於閾值爲給定最大值 高於閾值爲0

                  THRESH_TRUNC    低於閾值,保持原來像素不變,高於閾值,爲閾值

                  THRESH_TOZERO 低於閾值爲0,高於閾值保持原來值比邊

                  THRESH_TOZERO_INV 低於閾值保持原來值比邊,高於閾值爲0

         API:void adaptiveThreshold(源,目的,double 最大值,int 自適應算法類型,int 閾值類型,int 自適應            算法的鄰域尺寸,double 減去平均或者加權平均中的常數值).

                  注:該算法是自適應閾值化,自動根據鄰域中一個範圍的值肯定某一點的肯定像素閾值,源和目的都須要時單通道圖像,閾值類型必須爲THRESH_BINARY或者是THRESH_BINARY_INV的一種,自適應算法有兩種選擇,ADAPTIVE_THRESH_MEAN_C  以鄰域尺寸內平均值爲閾值,ADAPTIVE_THRESH_GAUSSIAN_C 鄰域矩陣值與高斯窗口函數交叉相關的加權綜合

 

         使用例程以下

Mat srcImage;
Mat srcSingleImage;

//正y常¡ê閾D值¦Ì化¡¥
Mat thresholdImage;
const int g_thresholdMax = 255;
int g_thresholdValue;
const int g_thresholdMaxMax = 255;
int g_thresholdMaxValue;

void onTrackBarThresholdValue(int pos,void* userData);
void onTrackBarThresholdMax(int pos,void* userData);


//自Á?適º¨º應®|閾D值¦Ì化¡¥
Mat adaptiveThresholdImage;
const int g_adaptiveThresholdMaxMax = 255;
int g_adaptiveThresholdMaxValue;

void onTrackBarAdaptiveThresholdMax(int pos,void* userData);


int main(int argc,char* argv[])
{
   srcImage = imread("F:\\opencv\\OpenCVImage\\adaptiveThreshold.png");
   if(srcImage.channels() == 1)
   {
       srcSingleImage = srcImage(Range(0,srcImage.rows),Range(0,srcImage.cols));
   }
   else
   {
       srcSingleImage = Mat(srcImage.rows, srcImage.cols, CV_8UC1);
       cvtColor(srcImage, srcSingleImage, CV_RGB2GRAY);
   }
   
   namedWindow("src image");
   
   g_thresholdValue = 100;
   g_thresholdMaxValue = 255;
   namedWindow("threshold image");
   createTrackbar("threshold max", "threshold image", &g_thresholdMaxValue, g_thresholdMaxMax,onTrackBarThresholdMax,0);
   createTrackbar("threshold value", "threshold image", &g_thresholdValue, g_thresholdMax,onTrackBarThresholdValue,0);
   onTrackBarThresholdValue(g_thresholdValue, 0);
   
   g_adaptiveThresholdMaxValue = 255;
   namedWindow("adaptiveThreshold image");
   createTrackbar("adaptiveThreshold Max", "adaptiveThreshold image", &g_adaptiveThresholdMaxValue, g_adaptiveThresholdMaxMax,onTrackBarAdaptiveThresholdMax,0);
   onTrackBarAdaptiveThresholdMax(g_adaptiveThresholdMaxValue, 0);
   
   imshow("src image", srcSingleImage);
   
   moveWindow("src image", 0, 0);
   moveWindow("threshold image", srcSingleImage.cols, 0);
   moveWindow("adaptiveThreshold image", srcSingleImage.cols*2, 0);
   
   waitKey(0);
   return 0;
}



//正y常¡ê閾D值¦Ì化¡¥,需¨¨要°a指?定¡§閾D值¦Ì以°?及¡ã最Á?大䨮值¦Ì
void onTrackBarThresholdValue(int pos,void* userData)
{
   if (g_thresholdMaxValue == 0)
   {
       imshow("threshold image", srcSingleImage);
   }
   else
   {
       threshold(srcSingleImage, thresholdImage, g_thresholdValue, (double)g_thresholdMaxValue, THRESH_BINARY);
       imshow("threshold image", thresholdImage);
   }
}
void onTrackBarThresholdMax(int pos,void* userData)
{
   if (g_thresholdMaxValue == 0)
   {
       imshow("threshold image", srcSingleImage);
   }
   else
   {
       threshold(srcSingleImage, thresholdImage, g_thresholdValue, (double)g_thresholdMaxValue, THRESH_BINARY);
       imshow("threshold image", thresholdImage);
   }
}


//自適應閾值化,只須要指定最大值就行了
void onTrackBarAdaptiveThresholdMax(int pos,void* userData)
{
   if(g_adaptiveThresholdMaxValue == 0)
   {
       imshow("adaptiveThreshold image", srcSingleImage);
   }
   else
   {
       adaptiveThreshold(srcSingleImage, adaptiveThresholdImage, g_adaptiveThresholdMaxValue, THRESH_BINARY, ADAPTIVE_THRESH_MEAN_C, 7, 0);
       imshow("adaptiveThreshold image", adaptiveThresholdImage);
   }
}
相關文章
相關標籤/搜索