日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV图像分割-watershed

發(fā)布時(shí)間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV图像分割-watershed 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
轉(zhuǎn)自:Tiger & Pi? http://blog.163.com/my_645/blog/static/369785222013310619742/ Watershed就是傳說(shuō)中的分水嶺算法, 它將一幅圖像看成是一塊有湖泊和山川組成的地形。 圖像灰度值大的像素對(duì)應(yīng)海拔高的山地, 灰度值低的像素對(duì)應(yīng)于海拔低的盆地。Watershed分割是模擬湖水上漲并在湖泊相遇處筑壩的過(guò)程。一般水是從湖泊的最低處灌進(jìn)去,最低點(diǎn)對(duì)應(yīng)于圖像的局部最低點(diǎn)。 但確定局部最低點(diǎn)的自動(dòng)話算法得到的結(jié)果往往不盡如人意, 所以常常要手動(dòng)指定marker點(diǎn)。 函數(shù)原型 void cvWatershed(Iplimage *src_image, CvArr* markers) 下面的代碼通過(guò)交互式的方式演示了watershed的過(guò)程,先在圖像的不同區(qū)域畫線,然后按w鍵運(yùn)行算法。 下圖左邊是原圖和指定的markers, 右邊是分割的mask圖像。

/************************************************************************/
/* 下面這一堆代碼真正的分水嶺代碼在cvWatershed( img0, markers )函數(shù)里面,其它
歸納起來(lái)為:實(shí)現(xiàn)鼠標(biāo)標(biāo)記圖像,制作markers標(biāo)記圖像,實(shí)現(xiàn)顏色填充效果。 */
/************************************************************************/

//
// ch9_watershed image
// This is an exact copy of the watershed.cpp demo in the OpenCV ../samples/c directory
//
// Think about using a morphologically eroded foreground and background segmented image as the template
// for the watershed algorithm to segment objects by color and edges for collecting
//

#include "stdio.h"
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <stdlib.h>

IplImage* marker_mask = 0;
IplImage* markers = 0;
IplImage* img0 = 0, *img = 0, *img_gray = 0, *wshed = 0;
CvPoint prev_pt = {-1,-1};

void on_mouse(int event, int x, int y, int flags, void* param)
{
if(!img)
return;

if(event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON))
// 如果鼠標(biāo)左鍵彈起或鼠標(biāo)左鍵沒有按下
prev_pt = cvPoint(-1,-1);
else if(event == CV_EVENT_LBUTTONDOWN)
// 如果鼠標(biāo)左鍵按下
prev_pt = cvPoint(x,y);
else if(event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))
// 如果鼠標(biāo)移動(dòng)且左鍵按下
{
CvPoint pt = cvPoint(x,y);
if( prev_pt.x < 0 )
prev_pt = pt;
cvLine(marker_mask, prev_pt, pt, cvScalarAll(255), 5, 8, 0);
// 實(shí)際標(biāo)記 marker_mask 才會(huì)被算法用到
cvLine(img, prev_pt, pt, cvScalarAll(255), 5, 8, 0);
// img標(biāo)記只便于用戶觀察
prev_pt = pt;
cvShowImage("image", img);
}
}


int main()
{
printf( "Hot keys: \n"
"\tESC - quit the program\n"
"\tr - restore the original image\n"
"\tw or ENTER - run watershed algorithm\n"
"\t\t(before running it, roughly mark the areas on the image)\n"
"\t (before that, roughly outline several markers on the image)\n");

char* filename = "lena.BMP";
CvRNG rng = cvRNG(-1);
// 定義一個(gè)隨機(jī)化生成器并初始化為-1,配合下面cvRandInt(&rng)生成隨機(jī)數(shù),現(xiàn)在知道為什么會(huì)變顏色了吧

if((img0 = cvLoadImage(filename,1)) == 0)
return 0;

cvNamedWindow("image", 1);
cvNamedWindow("watershed transform", 1);

img = cvCloneImage(img0);
// 用于顯示的原圖像
img_gray = cvCloneImage(img0);
// 用于和分割出的顏色塊進(jìn)行混合
wshed = cvCreateImage(cvGetSize(img), 8, 3);
// 用于存儲(chǔ)分割出的顏色塊和最后的效果圖
marker_mask = cvCreateImage(cvGetSize(img), 8, 1);
// 用于記錄用戶標(biāo)記區(qū)域的畫布,并在此基礎(chǔ)上制作用于分水嶺算法使用的markers
markers = cvCreateImage(cvGetSize(img), IPL_DEPTH_32S, 1);
cvCvtColor(img, marker_mask, CV_BGR2GRAY);
cvCvtColor(marker_mask, img_gray, CV_GRAY2BGR);

cvZero(marker_mask);
cvZero( wshed );
cvShowImage( "image", img );
cvShowImage( "watershed transform", wshed );

cvSetMouseCallback("image", on_mouse, 0);
// 從這兒開始實(shí)現(xiàn)鼠標(biāo)標(biāo)記功能,具體可查ICVL

for(;;)
{
char c = cvWaitKey();

if( c == 27 )
break;

if( c == 'r' )
{
cvZero(marker_mask);
cvCopy(img0, img);
cvShowImage("image", img);
}

if(c == 'w')
{
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = 0;

int comp_count = 1;
// 粗看以為這是記錄輪廓數(shù)目呢,其實(shí)不然,他將把每個(gè)輪廓設(shè)為同一像素值
cvFindContours( marker_mask, storage, &contours, sizeof(CvContour),
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

cvZero( markers );
for( ; contours != 0; contours = contours->h_next, comp_count++)
{
cvDrawContours( markers, contours, cvScalarAll(comp_count+1),
cvScalarAll(comp_count+1), -1, -1, 8, cvPoint(0,0) );
}
// 上面這些最后得到markers 將會(huì)是一些數(shù)值塊,每個(gè)輪廓區(qū)域內(nèi)都有同一像素值
// 到此時(shí)Watershed 終于得到了它如饑似渴的 markers 這個(gè)markers 中記錄了剛剛
// 用戶用鼠標(biāo)勾勒的感興趣區(qū)域

CvMat* color_tab;
color_tab = cvCreateMat(1, comp_count, CV_8UC3);
// 構(gòu)造一個(gè)一維8bit無(wú)符號(hào)3通道元素類型的矩陣,用來(lái)記錄一些隨機(jī)的顏色
for(int i = 0; i < comp_count; i++)
{
uchar* ptr = color_tab->data.ptr + i*3;
ptr[0] = (uchar)(cvRandInt(&rng)%180 + 50);
ptr[1] = (uchar)(cvRandInt(&rng)%180 + 50);
ptr[2] = (uchar)(cvRandInt(&rng)%180 + 50);
}

{// 千呼萬(wàn)喚始出來(lái)的cvWatershed
double t = (double)cvGetTickCount();
cvWatershed(img0, markers);
t = (double)cvGetTickCount() - t;
printf( "exec time = %gms\n", t/(cvGetTickFrequency()*1000.) );
// 上面的t用來(lái)計(jì)算此算法運(yùn)行時(shí)間

/************************************************************************/
/* markers中包含了一些用戶感興趣的區(qū)域,每個(gè)區(qū)域用1、2、3。。一些像素值標(biāo)注,經(jīng)過(guò)
此算法后,markers會(huì)變成什么樣呢?要知道m(xù)arkers中標(biāo)注的只是用戶用鼠標(biāo)輕描淡寫的
一些區(qū)域,把這些區(qū)域想像成一些湖泊,如果只有一個(gè)區(qū)域,則代表整幅圖將會(huì)被這一個(gè)
湖泊淹沒,上面color_tab 正是用來(lái)記錄每個(gè)湖泊的顏色。如果用戶標(biāo)注了兩個(gè)區(qū)域,則
湖泊會(huì)沿著這兩個(gè)區(qū)域蔓延,直到把圖片分成兩個(gè)湖泊,這兩個(gè)湖泊不是無(wú)規(guī)律的,而是
盡可能把圖像的輪廓分隔開。如標(biāo)注多個(gè)區(qū)域,則將形成多種顏色的湖泊,此算法會(huì)把把
每個(gè)湖泊的分水嶺賦為 -1,即用來(lái)分隔這些湖泊,下面圖片展示了這些湖泊把整幅圖都分
隔開了 */
/************************************************************************/
}

// paint the watershed image
for(int i = 0; i < markers->height; i++)
for(int j = 0; j < markers->width; j++)
{
int idx = CV_IMAGE_ELEM( markers, int, i, j );
// idx得到了markers 在(i, j)坐標(biāo)的的像素值,這個(gè)值對(duì)應(yīng)color_tab中的一種顏色
// 因?yàn)閙arkers 中的像素值就是用1-comp_count 的像素值標(biāo)注的
uchar* dst = &CV_IMAGE_ELEM( wshed, uchar, i, j*3 );
// dst得到了wshed圖像 (i, j)像素?cái)?shù)據(jù)的首地址,因?yàn)槌?是因?yàn)?通道

if( idx == -1 )
// 在wshed圖像中將markers 中得到的分水嶺標(biāo)記為白色,原先-1將顯示黑色
dst[0] = dst[1] = dst[2] = (uchar)255;
else if( idx <= 0 || idx > comp_count )
dst[0] = dst[1] = dst[2] = (uchar)0; // should not get here
else
{
uchar* ptr = color_tab->data.ptr + (idx-1)*3;
// 指向idx 所對(duì)應(yīng)的顏色通道,這些顏色是上面隨機(jī)生成的
dst[0] = ptr[0]; dst[1] = ptr[1]; dst[2] = ptr[2];
// 把對(duì)應(yīng)的像素值賦給wshed 圖像
}
}

cvAddWeighted( wshed, 0.5, img_gray, 0.5, 0, wshed );
// 可以注釋掉看下效果
cvShowImage( "watershed transform", wshed );
cvReleaseMemStorage( &storage );
cvReleaseMat( &color_tab );
}
}

return 1;
}

轉(zhuǎn)載于:https://www.cnblogs.com/April1314/p/3406988.html

總結(jié)

以上是生活随笔為你收集整理的OpenCV图像分割-watershed的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。