OpenCV自学笔记6. 图像分割

来源:互联网 发布:yum install CMake 编辑:程序博客网 时间:2024/06/04 17:44

图像分割

引言:
图像分割是图像预处理的重要步骤之一,它的主要目标是将图像划分为不同的区域,这些区域与真实世界中的物体具有一定的关联成分。图像分割的方法大体分为以下三种:基于阈值的分割、基于边缘的分割和基于区域的分割。其中基于区域的分割较为常用。OpenCV提供了 分水岭算法 和 GrabCut算法,可以快速实现图像的分割。

本小节使用的测试图像为:

这里写图片描述

————————————————————————–

使用分水岭算法进行图像分割

# -*- coding:utf-8 -*-import cv2import numpy as np# Step1. 加载图像img = cv2.imread('images/fruits.jpg')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Step2.阈值分割,将图像分为黑白两部分ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)cv2.imshow("thresh", thresh)# Step3. 对图像进行“开运算”,先腐蚀再膨胀kernel = np.ones((3, 3), np.uint8)opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)cv2.imshow("opening", opening)# Step4. 对“开运算”的结果进行膨胀,得到大部分都是背景的区域sure_bg = cv2.dilate(opening, kernel, iterations=3)cv2.imshow("sure_bg", sure_bg)# Step5.通过distanceTransform获取前景区域dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)ret, sure_fg = cv2.threshold(dist_transform, 0.6 * dist_transform.max(), 255, 0)cv2.imshow("sure_fg", sure_fg)# Step6. sure_bg与sure_fg相减,得到既有前景又有背景的重合区域sure_fg = np.uint8(sure_fg)unknow = cv2.subtract(sure_bg, sure_fg)# Step7. 连通区域处理ret, markers = cv2.connectedComponents(sure_fg)markers = markers + 1markers[unknow==255] = 0# Step8.分水岭算法markers = cv2.watershed(img, markers)img[markers == -1] = [0, 255, 0]cv2.imshow("dst", img)cv2.waitKey(0)

各个步骤的运行结果如图:

这里写图片描述

最后的效果为:

这里写图片描述

————————————————————————–

使用GrubCut算法进行图像分割

本小节使用的测试图像为:

这里写图片描述

# -*- coding:utf-8 -*-import cv2import numpy as np# Step1. 加载图像img = cv2.imread('images/messi5.jpg')# Step2. 创建掩模、背景图和前景图mask = np.zeros(img.shape[:2], np.uint8) # 创建大小相同的掩模bgdModel = np.zeros((1,65), np.float64) # 创建背景图像fgdModel = np.zeros((1,65), np.float64) # 创建前景图像# Step3. 初始化矩形区域# 这个矩形必须完全包含前景(相当于这里的梅西)rect = (50,50,450,290)# Step4. GrubCut算法,迭代5次# mask的取值为0,1,2,3cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT) # 迭代5次# Step5. mask中,值为2和0的统一转化为0, 1和3转化为1 mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')img = img * mask2[:,:,np.newaxis] # np.newaxis 插入一个新维度,相当于将二维矩阵扩充为三维cv2.imshow("dst", img)cv2.waitKey(0)

GrubCut算法的参数如下:

这里写图片描述

注意:

Initially user draws a rectangle around the foreground region (foreground region shoule be completely inside the rectangle)
也就是说,前景图必须完全包含在矩形内,即:初始化的矩形必须完全包含梅西~

GrubCut算法的运行结果如下:

这里写图片描述


附录:用C++写的GrubCut算法小例子

参考:http://www.cnblogs.com/mikewolf2002/p/3330390.html

grubcut.cpp

#include <opencv2/opencv.hpp>#include <iostream>using namespace cv;using namespace std;int main() {    string path = "images/test4.jpg";    Mat img = imread(path); // 读入图像    Mat bgModel, fgModel, mask;    Rect rect;    rect.x = 20;    rect.y = 30;    rect.width = img.cols - (rect.x << 1);    rect.height = img.rows - (rect.y << 1);    //rectangle(img, rect, Scalar(0, 0, 255), 3, 8, 0);//用矩形画矩形窗      //循环执行3次,这个可以自己设置    grabCut(img, mask, rect, bgModel, fgModel, 3, GC_INIT_WITH_RECT);    compare(mask, GC_PR_FGD, mask, CMP_EQ);    Mat foreground(img.size(), CV_8UC3, Scalar(255, 255, 255));    img.copyTo(foreground, mask);    imshow("foreground", foreground);    waitKey(0);    return 0;}

测试用图为:
这里写图片描述

背景分割的结果如下:
可以看到,准确分割出了建筑物的主体部分
这里写图片描述

这里写图片描述

原创粉丝点击