欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV基于距離變換和分水嶺實(shí)現(xiàn)圖像分割

 更新時(shí)間:2022年09月27日 16:31:55   作者:肖愛Kun  
圖像分割是根據(jù)灰度、顏色、紋理和形狀等特征,把圖像分成若干個(gè)特定的、具有獨(dú)特性質(zhì)的區(qū)域。本文將基于距離變換和分水嶺實(shí)現(xiàn)圖像分割,需要的可以了解一下

一.圖像分割

圖像分割是根據(jù)灰度、顏色、紋理和形狀等特征,把圖像分成若干個(gè)特定的、具有獨(dú)特性質(zhì)的區(qū)域,這些特征在同一區(qū)域內(nèi)呈現(xiàn)出相似性,而在不同區(qū)域間呈現(xiàn)出明顯的差異性,并提出感興趣目標(biāo)的技術(shù)和過程。 它是由圖像處理到圖像分析的關(guān)鍵步驟。從數(shù)學(xué)角度來看,圖像分割是將數(shù)字圖像劃分成互不相交的區(qū)域的過程。圖像分割的過程也是一個(gè)標(biāo)記過程,即把屬于同一區(qū)域的像索賦予相同的編號(hào)。

其目的是將圖像中像素根據(jù)一定的規(guī)則分為若干(N)個(gè)聚(cluster)集合,每個(gè)集合包含一類像素。將對(duì)象在背景提取出來。

二.基于距離變換和分水嶺的圖像分割

分水嶺法(Meyer)是一種基于拓?fù)淅碚摰臄?shù)學(xué)形態(tài)學(xué)的分割方法,其基本思想是把圖像看作是測(cè)地學(xué)上的拓?fù)涞孛?,圖像中每一點(diǎn)像素的灰度值表示該點(diǎn)的海拔高度,每一個(gè)局部極小值及其影響區(qū)域稱為集水盆,而集水盆的邊界則形成分水嶺。該算法的實(shí)現(xiàn)可以模擬成洪水淹沒的過程,圖像的最低點(diǎn)首先被淹沒,然后水逐漸淹沒整個(gè)山谷。當(dāng)水位到達(dá)一定高度的時(shí)候?qū)?huì)溢出,這時(shí)在水溢出的地方修建堤壩,重復(fù)這個(gè)過程直到整個(gè)圖像上的點(diǎn)全部被淹沒,這時(shí)所建立的一系列堤壩就成為分開各個(gè)盆地的分水嶺。分水嶺算法對(duì)微弱的邊緣有著良好的響應(yīng),但圖像中的噪聲會(huì)使分水嶺算法產(chǎn)生過分割的現(xiàn)象。

距離變換API函數(shù)接口

距離變換用于計(jì)算圖像中每一個(gè)非零點(diǎn)像素與其周圍最近的零點(diǎn)像素之間的距離,返回的值保存了每一個(gè)非零點(diǎn)與最近零點(diǎn)的距離信息;在圖像上的體現(xiàn)為圖像上越亮的點(diǎn),代表了離零點(diǎn)的距離越遠(yuǎn)。

void distanceTransform( 
InputArray src,  
OutputArray dst,
OutputArray labels,
int distanceType,
int maskSize,
int labelType=DIST_LABEL_CCOMP
);

參數(shù)說明

(1)src是單通道的8bit的二值圖像(只有0或1)

(2)dst表示的是計(jì)算距離的輸出圖像,可以使單通道32bit浮點(diǎn)數(shù)據(jù)

(3)distanceType表示的是選取距離的類型,可以設(shè)置為CV_DIST_L1,CV_DIST_L2,CV_DIST_C等,具體如下:

DIST_USERUser defined distance
DIST_L1=1distance = |x1-x2| + |y1-y2
DIST_L2the simple euclidean distance
DIST_Cdistance = max(|x1-x2|,|y1-y2|)
DIST_L12L1-L2 metric: distance =2(sqrt(1+x*x/2) - 1))
DIST_FAIRdistance = c^2(|x|/c-log(1+|x|/c)),c = 1.3998
DIST_WELSCHdistance = c2/2(1-exp(-(x/c)2)), c= 2.9846
DIST_HUBERdistance = |x|<c ? x^2/2 :c(|x|-c/2), c=1.345

(4)maskSize表示的是距離變換的掩膜模板,可以設(shè)置為3,5或CV_DIST_MASK_PRECISE,對(duì) CV_DIST_L1 或CV_DIST_C 的情況,參數(shù)值被強(qiáng)制設(shè)定為 3, 因?yàn)?×3 mask 給出5×5 mask 一樣的結(jié)果,而且速度還更快。

DIST_MASK_3mask=3
DIST_MASK_5mask=5
DIST_MASK-PRECISE 

(5)labels表示可選輸出2維數(shù)組;

(6)labelType表示的是輸出二維數(shù)組的類型,8位或者32位浮點(diǎn)數(shù),圖像是單一通道,并且大小與輸入圖像一致

watershed 分水嶺函數(shù)API接口

void watershed( InputArray image, InputOutputArray markers );

參數(shù)說明

(1)參數(shù) image,必須是一個(gè)8bit3通道彩色圖像矩陣序列。

(2) 輸入或輸出32位單通道的標(biāo)記,和圖像一樣大小。(輸入高峰輪廓標(biāo)記);在執(zhí)行分水嶺函數(shù)watershed之前,必須對(duì)第二個(gè)參數(shù)markers進(jìn)行處理,它應(yīng)該包含不同區(qū)域的輪廓,每個(gè)輪廓有一個(gè)自己唯一的編號(hào),輪廓的定位可以通過Opencv中findContours方法實(shí)現(xiàn),這個(gè)是執(zhí)行分水嶺之前的要求。

算法會(huì)根據(jù)markers傳入的輪廓作為種子(也就是所謂的注水點(diǎn)),對(duì)圖像上其他的像素點(diǎn)根據(jù)分水嶺算法規(guī)則進(jìn)行判斷,并對(duì)每個(gè)像素點(diǎn)的區(qū)域歸屬進(jìn)行劃定,直到處理完圖像上所有像素點(diǎn)。而區(qū)域與區(qū)域之間的分界處的值被置為“-1”,以做區(qū)分。

代碼實(shí)現(xiàn)

1、將白色背景改為黑色,為后面的變換做準(zhǔn)備;

2、使用filter2D與Laplace算子實(shí)現(xiàn)圖像對(duì)比度的提高;sharpen銳化

3、通過threshold()轉(zhuǎn)換為二值圖像;

4、距離變換;

5、對(duì)距離變換的結(jié)果歸一化到0-1之間;

6、使用閾值,再次二值化,得到標(biāo)記;

7、腐蝕(erode)得到每個(gè)Peak;(peak : 山峰,山頂 )

8、發(fā)現(xiàn)輪廓findContours;

9、繪制輪廓;

10、分水嶺變換;

11、對(duì)每個(gè)分割區(qū)域著色輸出結(jié)果;

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
 
using namespace std;
using namespace cv;
 
int main(int argc, char** argv) {
	char input_win[] = "input image";
	char watershed_win[] = "watershed segmentation demo";
	Mat src = imread("D:/vcprojects/images/cards.png");
	// Mat src = imread("D:/kuaidi.jpg");
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	imshow(input_win, src);
	// 1. change background
	for (int row = 0; row < src.rows; row++) {
		for (int col = 0; col < src.cols; col++) {
			if (src.at<Vec3b>(row, col) == Vec3b(255, 255, 255)) {
				src.at<Vec3b>(row, col)[0] = 0;
				src.at<Vec3b>(row, col)[1] = 0;
				src.at<Vec3b>(row, col)[2] = 0;
			}
		}
	}
	namedWindow("black background", CV_WINDOW_AUTOSIZE);
	imshow("black background", src);
 
	// sharpen
	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
	Mat imgLaplance;
	Mat sharpenImg = src;
	filter2D(src, imgLaplance, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
	src.convertTo(sharpenImg, CV_32F);
	Mat resultImg = sharpenImg - imgLaplance;
 
	resultImg.convertTo(resultImg, CV_8UC3);
	imgLaplance.convertTo(imgLaplance, CV_8UC3);
	imshow("sharpen image", resultImg);
	// src = resultImg; // copy back
 
	// convert to binary
	Mat binaryImg;
	cvtColor(src, resultImg, CV_BGR2GRAY);
	threshold(resultImg, binaryImg, 40, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("binary image", binaryImg);
 
	Mat distImg;
	distanceTransform(binaryImg, distImg, DIST_L1, 3, 5);
	normalize(distImg, distImg, 0, 1, NORM_MINMAX);
	imshow("distance result", distImg);
	
	// binary again
	threshold(distImg, distImg, .4, 1, THRESH_BINARY);
	Mat k1 = Mat::ones(13, 13, CV_8UC1);
	erode(distImg, distImg, k1, Point(-1, -1));
	imshow("distance binary image", distImg);
 
	// markers 
	Mat dist_8u;
	distImg.convertTo(dist_8u, CV_8U);
	vector<vector<Point>> contours;
	findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
 
	// create makers
	Mat markers = Mat::zeros(src.size(), CV_32SC1);
	for (size_t i = 0; i < contours.size(); i++) {
		drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i) + 1), -1);
	}
	circle(markers, Point(5, 5), 3, Scalar(255, 255, 255), -1);
	imshow("my markers", markers*1000);
 
	// perform watershed
	watershed(src, markers);
	Mat mark = Mat::zeros(markers.size(), CV_8UC1);
	markers.convertTo(mark, CV_8UC1);
	bitwise_not(mark, mark, Mat());
	imshow("watershed image", mark);
 
	// generate random color
	vector<Vec3b> colors;
	for (size_t i = 0; i < contours.size(); i++) {
		int r = theRNG().uniform(0, 255);
		int g = theRNG().uniform(0, 255);
		int b = theRNG().uniform(0, 255);
		colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
	}
 
	// fill with color and display final result
	Mat dst = Mat::zeros(markers.size(), CV_8UC3);
	for (int row = 0; row < markers.rows; row++) {
		for (int col = 0; col < markers.cols; col++) {
			int index = markers.at<int>(row, col);
			if (index > 0 && index <= static_cast<int>(contours.size())) {
				dst.at<Vec3b>(row, col) = colors[index - 1];
			}
			else {
				dst.at<Vec3b>(row, col) = Vec3b(0, 0, 0);
			}
		}
	}
	imshow("Final Result", dst);
 
	waitKey(0);
	return 0;
}

圖像處理效果

輸入原圖像和銳化圖像 

原圖和黑背景圖(背景應(yīng)為黑色) 

threshold轉(zhuǎn)化的二值化圖片和距離變換結(jié)果圖

 距離變換結(jié)果圖和二值化圖像

到此這篇關(guān)于OpenCV基于距離變換和分水嶺實(shí)現(xiàn)圖像分割的文章就介紹到這了,更多相關(guān)OpenCV圖像分割內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 總結(jié)c++性能優(yōu)化策略

    總結(jié)c++性能優(yōu)化策略

    在本篇文章中小編給大家總結(jié)了關(guān)于C++的性能優(yōu)化策略的相關(guān)知識(shí)點(diǎn),對(duì)此有興趣的朋友可以參考學(xué)習(xí)下。
    2018-03-03
  • C++如何獲取系統(tǒng)信息 C++獲取IP地址、硬件信息等

    C++如何獲取系統(tǒng)信息 C++獲取IP地址、硬件信息等

    這篇文章主要為大家詳細(xì)介紹了C++如何獲取系統(tǒng)信,C++獲取IP地址、硬件信息等,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • 成員函數(shù)的重載、覆蓋與隱藏詳細(xì)解析

    成員函數(shù)的重載、覆蓋與隱藏詳細(xì)解析

    成員函數(shù)的重載、覆蓋(override)與隱藏很容易混淆,C++程序員必須要搞清楚概念,否則錯(cuò)誤將防不勝防
    2013-10-10
  • 深入java線程池的使用詳解

    深入java線程池的使用詳解

    本篇文章是對(duì)java線程池的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++語(yǔ)言實(shí)現(xiàn)拼圖游戲詳解

    C++語(yǔ)言實(shí)現(xiàn)拼圖游戲詳解

    這篇文章主要為大家詳細(xì)介紹了C++基于EasyX庫(kù)實(shí)現(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • OpenCV基于背景減除實(shí)現(xiàn)行人計(jì)數(shù)

    OpenCV基于背景減除實(shí)現(xiàn)行人計(jì)數(shù)

    本文主要介紹了如何使用OpenCV C++對(duì)視頻中的人流量進(jìn)行統(tǒng)計(jì)。文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)OpenCV有一定的幫助,需要的可以了解一下
    2022-01-01
  • MFC繪制不規(guī)則窗體的方法

    MFC繪制不規(guī)則窗體的方法

    這篇文章主要介紹了MFC繪制不規(guī)則窗體的方法,涉及MFC窗體操作的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • c++選擇排序詳解

    c++選擇排序詳解

    選擇排序(Selection sort)是一種簡(jiǎn)單直觀的排序算法。它的工作原理是每一次從無(wú)序組的數(shù)據(jù)元素中選出最?。ɑ蜃畲螅┑囊粋€(gè)元素,存放在無(wú)序組的起始位置,無(wú)序組元素減少,有序組元素增加,直到全部待排序的數(shù)據(jù)元素排完。
    2017-05-05
  • VScode+ESP32簡(jiǎn)單環(huán)境搭建

    VScode+ESP32簡(jiǎn)單環(huán)境搭建

    本文章向大家介紹ESP32-C3搭建環(huán)境教程,主要包括ESP32-C3搭建環(huán)境教程使用實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C++ BloomFilter布隆過濾器應(yīng)用及概念詳解

    C++ BloomFilter布隆過濾器應(yīng)用及概念詳解

    布隆過濾器是由布?。˙urton Howard Bloom)在1970年提出的 一種緊湊型的、比較巧妙的概率型數(shù)據(jù)結(jié)構(gòu),特點(diǎn)是高效地插入和查詢,可以用來告訴你 “某樣?xùn)|西一定不存在或者可能存在”,它是用多個(gè)哈希函數(shù),將一個(gè)數(shù)據(jù)映射到位圖結(jié)構(gòu)中
    2023-03-03

最新評(píng)論