热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python计算机视觉基于OpenCV的图像分割和图像融合系统

python计算机视觉--基于OpenCV的图像分割和图像融合系统-目录前言一、需求分析二、概要设计2.1 基本原理                           

目录

前言

一、需求分析

二、概要设计

2.1 基本原理                                                                                                                                     

2.2 界面设计

三、详细设计

3.1 系统流程图

3.2 数据集

3.3 代码实现

3.3.1 利用deeplabV3模型分割

 3.3.2 利用grabCut分割

3.3.3 Alpha Blending图像融合

3.3.4 UI界面

四、实验结果与分析

总结


前言

记录记录计算机视觉期末大作业,利用OpenCV实现了人像的前后景分割,GrabCut可以实现所有类型的图像分割,DeeplavbV3模型调用飞桨的deeplabv3p_xception65_humanseg,该模型只能用于人像抠图。

环境:python3.8.5,pycharm,OpenCV库


一、需求分析

        现实生活中,我们经常会遇到将图像前景和背景分开的情况,比如证件照背景替换。在一幅图像中,人们可能只对其中的部分目标感兴趣,这些目标通常占据一定的区域,并且在某些特性上和临近的图像有差别。因此我们需要将图像前景与背景分割,以便用于产品检验,目标提取,图像融合等方面。所以系统的设计应具有如下方面:

(1)系统的输入;

        用户点击选择图片按钮,将一张需要分割的图片读入系统。

(2)系统的输出;

        通过分割算法将分割所得前景图像显示在界面上,用户可对结果图进行背景替换或保存。

(3)系统实现的功能。

        系统实现了利用百度开源库deeplabv3+和grabCut实现了图像前景和背景的分割,利用Alpha blending实现了背景替换,Poisson Blending实现两幅图像的融合,通过pyqt设计UI界面实现了图像的点击操作。

二、概要设计

2.1 基本原理                                                                                                                                     

(1)百度开源库deeplabV3+

        通过查阅资料新了解了deeplabV3+:DeeplabV3+语义分割领域模型效果非常好的方法。DeeplabV3+主要在原有模型的基础上引入了可任意控制编码器提取特征的分辨率,通过在Encoder部分加入大量空洞卷积平衡精度和耗时。在不损失信息的情况下,加大了感受野,让每个卷积输出都包含较大范围的信息。

空洞卷积:

                                                        图 2-1 空洞卷积示意图

加入了空洞卷积,调整filters的接受野,如上图所示,左图中标准卷积中的卷积核大小为 3x3,其感受野也为 3x3,在卷积核中间插入 0 之后变为右图空洞卷积,其中实际参与计算的卷积核大小仍为 3x3,而感受野已经扩大到了 5x5。感受野增大后可以检测分割大目标,另一方面分辨率高了可以精确定位目标。

DeeplabV3+的模型介绍:

                                                        图2-2 DeeplabV3模型

 输入一张图片,首先进入Encoder进行特征提取,利用深度卷积神经网络可以得到两个特征层,浅层特征送入Decoder,对深层特征利用不同膨胀率的膨胀卷积进行更深层次的特征提取,不同膨胀率的膨胀卷积提高了网络的感受野,之后对堆叠的特征进行过滤后送入Decoder,经过上采样和原来的浅层特征卷积结果融合,再次进行3x3特征特取,最后将输出图像调整到和输入图像一样,得到最终结果。

 (2)图像分割:grabCut算法

graph Cut算法示意图:

                                                         图2-3 graph Cut算法示意图

Grabcut是基于图割(graph cut)实现的图像分割算法,它需要用户输入一个矩形框作为分割目标位置,实现对目标与背景的分割,位于框内部的属于前景,框外面的属于背景。Graph cut 算法是根据该像素点灰度值,在前景和背景中的灰度值直方图所占的比例来计算前景和背景概率的,求某个像素点lp与相邻像素点lq之间的(灰度值)差异,lp-lq的值越大,两个像素之间的边越是应该是割边。在Grab cut 中,不是以灰度为基准,而是以BGR三通道衡量两像素的相似性,采用欧式距离计算两个像素之间的差异。在计算区域项时,采用了高斯混合模型,在多个模型计算式,选取概率最大的一个。区域项反映的是,像素样本集合的整体特性,边界项反映的是两个像素之间的差异。在经过处理得到的掩膜中有四个值,分别表示前景,背景,可能前景,可能背景,合并前景和可能前景得到分割结果。

2.2 界面设计

界面由三部分组成,左侧是功能按钮区,包括开始分割、保存、背景替换、拍摄图像按钮,中间是图像显示区,有original Image 和result Image;下面是图片选择按钮和运行时间显示区。下图所示:

                                                         图2-4 初始化界面

                                                        图2-5 grabCut分割示例

三、详细设计

3.1 系统流程图

        首先读取图像并进行USM锐化,增强图像细节,便于提取前景;手动选择目标前景区域ROI,进行grabCut图像分割,提取前景ROI区域的二值图像;将得到的前景ROI区域二值图像利用形态学滤波进行开运算消除细微干扰,接着与锐化图像进行与运算得到前景图像。

                                                     图2-6 grabCut图像分割示意图

Alpha Blending图像融合实现:读入分割得到的前景图像,分离出alpha掩膜,对掩膜腐蚀过滤掉其中白点,对腐蚀图像膨胀消除噪声,利用alpha掩膜对前景和背景进行加权,得到融合结果图像。

                                                    图2-7 Alpha Blending流程图

3.2 数据集

选取作为分割和融合测试的数据集如下,可任选电脑上图片进行测试:

3.3 代码实现

3.3.1 利用deeplabV3模型分割

将图像路径传入函数,调用飞桨训练模型实现分割,保存分割的前景图像,将轮廓图像进行阈值处理,图像腐蚀去除噪声,再进行图像膨胀处理恢复原来形状,删除累计分割结果,减少存储。

# 导入库
from PIL import Image
import numpy as np
import cv2
import os
# PaddleHub是基于PaddlePaddle生态下的预训练模型管理和迁移学习工具
# 可以结合预训练模型更便捷地开展迁移学习工作,通过PaddleHub,可以便捷地获取PaddlePaddle生态下的所有预训练模型
import paddlehub as hub
import matplotlib.pyplot as plt
import matplotlib.image as mping


def img_remove(remove_img_path):
    # 删除原有路径中.jpg格式文件
    for root, dirs, files in os.walk(remove_img_path):
        for file in files:
            file_path = os.path.join(root, file)
            if str(file_path.split('.')[-1]).upper() == 'PNG':
                os.remove(file_path)
    print('删除完成')

# 用matplotlib显示中文,避免乱码
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号


def paddle_cut_Image(imgPath):
    """利用deeplabv3p分割图像"""
   
    # 1.获取图片路径,传入模型
    test_img_path = imgPath

    # 2.调用飞桨训练模型
    # 调用飞桨的deeplabv3p_xception65_humanseg,该模型用于人像抠图
    moddle = hub.Module(name="deeplabv3p_xception65_humanseg")
   
    # 训练模型并预测模型,打印结果(获取到抠图人像)
    result = moddle.segmentation(images=[cv2.imread(test_img_path)], visualization=True,
                                 output_dir='../humanseg_output')

    # 3.保存抠出的前景图像
    paddle_fore_img = mping.imread(result[0]['save_path'])
    mping.imsave("paddle_output/paddle_output.png", paddle_fore_img)
   
    # 4.保存轮廓图像
    res_image = Image.fromarray(np.uint8(result[0]['data']))
    path = "paddle_mask/paddle_mask.png"
    res_image.save(path)
    # 加载保存的轮廓并显示,接着对其进行二值化处理,然后进行图像的腐蚀膨胀操作,得到输出结果,根据结果调整参数值。
    counter_img_path = path
    img_counter = cv2.imread(counter_img_path)
    # 灰度图像
    img_gray = cv2.cvtColor(img_counter, cv2.COLOR_BGR2GRAY)
    # 阈值处理,图像二值化(ret:阈值,thresh1:阈值化后的图像)
    ret, thresh1 = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY)
    # getStructuringElement( ) 返回指定形状和尺寸的结构元素
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
    # 图像腐蚀,去除了噪声,但是会压缩图像。
    erode = cv2.erode(thresh1, kernel, iteratiOns=2)
    # 对腐蚀的图像膨胀处理,可以去除噪声,并且保持原有形状
    dilate = cv2.dilate(erode, kernel, iteratiOns=2)
    cv2.imwrite(path, dilate)
    # cv2.imshow('dilate',dilate)
    # # cv2.imshow('erode',erode)
    # # cv2.imshow('gray_img',img_gray)
    # # cv2.imshow('binary_img',thresh1)
    # # cv2.imshow('counter_img',img_counter)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()

    # 5.清理文件夹残存图像
    remove_img_path = r'/humanseg_output'
    img_remove(remove_img_path)

    current_working_dir = os.getcwd()
    paddle_fore_img_path = os.path.join(current_working_dir, "paddle_output\paddle_output.png")

    return paddle_fore_img_path

 3.3.2 利用grabCut分割

对图像进行USM锐化增强:通过增加图像边缘的对比度来锐化并给图像添加细节。USM锐化增强方法(Unsharpen Mask):

1.先对原图高斯模糊,用原图减去系数x高斯模糊的图像

2.再把值Scale到0~255的RGB像素范围

3.公式:(原图像-w*高斯模糊)/(1-w);w表示权重(0.1~0.9),默认0.6

优点:可以去除一些细小细节的干扰和噪声,比卷积更真实。

读取图像并进行USM锐化,增强图像细节,便于提取前景;手动选择目标前景区域ROI,进行grabCut图像分割,提取前景ROI区域的二值图像;将得到的前景ROI区域二值图像利用形态学滤波进行开运算消除细微干扰,接着与锐化图像进行与运算得到前景图像。

import os
import cv2
import numpy as np

def img_usm(img):
    # 对图像进行USM锐化增强:通过增加图像边缘的对比度来锐化并给图像添加细节
    # sigma = 5、15、25
    # 模糊图像(img:原图像,高斯核(等于0则根据sigmaX和sigmaY计算得出),标准差)
    blur_img = cv2.GaussianBlur(img, (0, 0), 5)
    # cv.addWeighted(图1,权重1, 图2, 权重2, gamma修正系数, dst可选参数, dtype可选参数)
    usmimg = cv2.addWeighted(img, 1.5, blur_img, -0.5, 0)
    cv2.convertScaleAbs(usmimg,usmimg)
    return usmimg

def img_grab_Cut(original_img,usmimg,rect):
    """进行grabCut图像分割"""
    # 掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;
    # 在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果
    mask = np.zeros(usmimg.shape[:2], np.uint8)  # 初始化蒙版图像
    bgdModel = np.zeros((1, 65), np.float64)  # 背景模型
    fgdModel = np.zeros((1, 65), np.float64)  # 前景模型
    cv2.grabCut(usmimg, mask, rect, bgdModel, fgdModel, 20, cv2.GC_INIT_WITH_RECT)  # 函数返回值为mask,bgdModel,fgdModel
   
    # 提取前景ROI区域二值图像
    foreground = np.zeros(original_img.shape[:3],np.uint8)
    foreground_roi = np.zeros(original_img.shape[:3], np.uint8)
    height = original_img.shape[0]
    width = original_img.shape[1]
    for row in range(height):
        for col in range(width):
            if mask[row,col] == 1 or mask[row,col] == 3:
                foreground_roi[row,col] = [255,255,255]

    cv2.imwrite('grabcut_mask/mask.png', foreground_roi)

    # 将得到的前景ROI区域二值图像进行开运算消除细微干扰后,和锐化图像进行与( and )操作,得到锐化后的前景区域
    # cv2.getStructuringElement:返回指定形状和尺寸的结构元素
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))

    # cv2.morphologyEx:形态学滤波,cv2.MORPH_OPEN:开运算(open):先腐蚀后膨胀的过程。开运算可以用来消除小黑点
    cv2.morphologyEx(foreground_roi, cv2.MORPH_OPEN, kernel)
    cv2.bitwise_and(foreground_roi, usmimg, foreground)
    return foreground


def main(imgPath):

    # 读取图像
    img = cv2.imread(imgPath)
    img2 = update_img_resize(img)

    # usm锐化
    usmimg = img_usm(img2)
    cv2.imshow("mask image", usmimg)

    rect = cv2.selectROI("mask image", usmimg, fromCenter=False, showCrosshair=False)
    print(rect)
    print(rect[0],rect[1],rect[2],rect[3])
    # 进行grabCut图像分割
    grabcut_img= img_grab_Cut(img2,usmimg, rect)
    # print(grabcut_img.shape,grabcut_img.dtype)
    print("分割完成")
    cv2.imwrite('grabcut_output/test.png', grabcut_img)  # 写入图片

    current_working_dir = os.getcwd()
    grab_fore_img_path = os.path.join(current_working_dir, "grabcut_output\\test.png")
    return grab_fore_img_path


def update_img_resize(img):
    """修改图像尺寸"""
    # result_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    result_img = cv2.resize(img,dsize=(480,640))
    return result_img



if __name__ == '__main__':
    main()

3.3.3 Alpha Blending图像融合

读入分割得到的前景图像,分离出alpha掩膜,对掩膜腐蚀过滤掉其中白点,腐蚀消除噪声的同时会压缩图像,接着对腐蚀图像膨胀,恢复原来形状,将alpha的值归一化在0~1之间作为加权系数,利用alpha掩膜对前景和背景进行加权,得到融合结果图像。

from Img_Segmentation import grabCut3
import cv2

def alpha_blending(fore_img_path,bg_img_path):
    """Alpha_Blending"""
    # foreGroundImage = cv2.imread('../paddle_output/paddle_output.png', -1)
    foreGroundImage = cv2.imread(fore_img_path, -1)
    foreGroundImage = grabCut3.update_img_resize(foreGroundImage)
    # 先将通道分离
    b, g, r, a = cv2.split(foreGroundImage)
    # 得到PNG图像前景部分,在这个图片中就是除去Alpha通道的部分
    foreground = cv2.merge((b, g, r))
    # 得到PNG图像的alpha通道,即alpha掩模
    alpha = cv2.merge((a, a, a))

    # 腐蚀膨胀过滤掉图中的白点
    erode_alpha = cv2.erode(alpha, None, iteratiOns=1)  # 图像被腐蚀后,去除了噪声,但是会压缩图像。
    alpha = cv2.dilate(erode_alpha, None, iteratiOns=1)  # 对腐蚀过的图像,进行膨胀处理,可以去除噪声,并且保持原有形状

    # background = cv2.imread(r'D:\python\RRJ\pycharmproject\Practice\chep2\bdd\green.png')
    background = cv2.imread(bg_img_path)
    background = grabCut3.update_img_resize(background)

    # 因为下面要进行乘法运算故将数据类型设为float,防止溢出
    foreground = foreground.astype(float)
    background = background.astype(float)

    cv2.imwrite("alpha/alpha.png", alpha)

    # 将alpha的值归一化在0-1之间,作为加权系数
    alpha = alpha.astype(float) / 255

    # cv2.imshow("alpha", alpha)
    # cv2.waitKey(0)

    # 将前景和背景进行加权,每个像素的加权系数即为alpha掩模对应位置像素的值,前景部分为1,背景部分为0
    foreground = cv2.multiply(alpha, foreground)
    background = cv2.multiply(1.0 - alpha, background)

    outImage = cv2.add(foreground, background)
    save_path = fore_img_path
    cv2.imwrite(save_path, outImage)

    # cv2.imshow("outImg", outImage / 255)
    # cv2.waitKey(0)
    return save_path

3.3.4 UI界面

import os
import time
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtCore import Qt

from Img_Segmentation import grabCut3, paddle_Image, poisson_blending, takephotos
from Img_Segmentation import Alpha_Blending

global imgNamepath
global flag


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("图像分割")
        # # 给MainWindow设置图标
        # MainWindow.setWindowIcon(QIcon(r'D:\\download\\xj.ico'))  # 路径错误找不到问题所在
        #
        # # 给MainWindow设置背景图片
        # palette = QPalette()
        # palette.setBrush(QPalette.Background, QBrush(QPixmap('D:\\python\\RRJ\\pycharmproject\\Practice\\chep2\\bdd'
        #                                                      '\\blue_bg.jpg')))
        # MainWindow.setPalette(palette)
        MainWindow.resize(1232, 852)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(10, 0, 1211, 791))
        self.widget.setStyleSheet("border:1px solid black;\n")
        self.widget.setObjectName("widget")
        self.label = QtWidgets.QLabel(self.widget)
        self.label.setGeometry(QtCore.QRect(0, 0, 1211, 101))
        self.label.setStyleSheet("font: 24pt \"Arial\";\n"
                                 "color:rgb(255, 170, 0);\n"
                                 "text-aligen:center;")
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.widget)
        self.label_2.setGeometry(QtCore.QRect(260, 180, 431, 451))
        self.label_2.setStyleSheet("background-color:rgb(255, 255, 255);")
        self.label_2.setText("原始图像显示区")
        self.label_2.setAlignment(Qt.AlignCenter)
        self.label_2.setStyleSheet("font: 14pt \"Arial\";\n")
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.widget)
        self.label_3.setGeometry(QtCore.QRect(750, 180, 431, 451))
        self.label_3.setStyleSheet("background-color:rgb(255, 255, 255);")
        self.label_3.setText("结果显示区")
        self.label_3.setAlignment(Qt.AlignCenter)
        self.label_3.setStyleSheet("font: 14pt \"Arial\";\n")
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(self.widget)
        self.label_4.setGeometry(QtCore.QRect(370, 130, 181, 41))
        self.label_4.setStyleSheet("border:0px;\n"
                                   "font: 14pt \"Arial\";\n")
        self.label_4.setObjectName("label_4")
        self.label_5 = QtWidgets.QLabel(self.widget)
        self.label_5.setGeometry(QtCore.QRect(890, 130, 131, 41))
        self.label_5.setStyleSheet("font: 14pt \"Arial\";\n"
                                   "border:0px;")
        self.label_5.setObjectName("label_5")
        self.pushButton = QtWidgets.QPushButton(self.widget)
        self.pushButton.setGeometry(QtCore.QRect(261, 660, 150, 51))
        self.pushButton.setStyleSheet("font: 12pt \"Arial\";")
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.widget)
        self.lineEdit.setGeometry(QtCore.QRect(410, 660, 771, 51))
        self.lineEdit.setStyleSheet("font: 12pt \"Arial\";\n")
        self.lineEdit.setObjectName("lineEdit")
        self.pushButton_2 = QtWidgets.QPushButton(self.widget)
        self.pushButton_2.setGeometry(QtCore.QRect(261, 720, 150, 51))
        self.pushButton_2.setStyleSheet("font: 12pt \"Arial\";")
        self.pushButton_2.setObjectName("pushButton_2")
        self.lineEdit_2 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit_2.setGeometry(QtCore.QRect(410, 720, 771, 51))
        self.lineEdit_2.setStyleSheet("font: 12pt \"Arial\";\n")
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.label_6 = QtWidgets.QLabel(self.widget)
        self.label_6.setGeometry(QtCore.QRect(0, 100, 221, 691))
        self.label_6.setText("")
        self.label_6.setObjectName("label_6")
        self.pushButton_3 = QtWidgets.QPushButton(self.widget)
        self.pushButton_3.setGeometry(QtCore.QRect(30, 200, 151, 51))
        self.pushButton_3.setStyleSheet("font: 14pt \"Arial\";")
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(self.widget)
        self.pushButton_4.setGeometry(QtCore.QRect(30, 290, 151, 51))
        self.pushButton_4.setStyleSheet("font: 14pt \"Arial\";\n")
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_5 = QtWidgets.QPushButton(self.widget)
        self.pushButton_5.setGeometry(QtCore.QRect(30, 460, 151, 51))
        self.pushButton_5.setStyleSheet("font: 14pt \"Arial\";")
        self.pushButton_5.setObjectName("pushButton_5")
        self.pushButton_6 = QtWidgets.QPushButton(self.widget)
        self.pushButton_6.setGeometry(QtCore.QRect(30, 550, 151, 51))
        self.pushButton_6.setStyleSheet("font: 14pt \"Arial\";")
        self.pushButton_6.setObjectName("pushButton_6")
        self.pushButton_7 = QtWidgets.QPushButton(self.widget)
        self.pushButton_7.setGeometry(QtCore.QRect(30, 370, 151, 51))
        self.pushButton_7.setStyleSheet("font: 14pt \"Arial\";")
        self.pushButton_7.setObjectName("pushButton_7")

        self.pushButton_8 = QtWidgets.QPushButton(self.widget)
        self.pushButton_8.setGeometry(QtCore.QRect(30, 640, 151, 51))
        self.pushButton_8.setStyleSheet("font: 14pt \"Arial\";")
        self.pushButton_8.setObjectName("pushButton_8")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1232, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        # 按钮关联函数
        self.pushButton.clicked.connect(self.openImage)
        self.pushButton_3.clicked.connect(self.start_paddle_Image)
        self.pushButton_4.clicked.connect(self.start_grabcut)
        self.pushButton_5.clicked.connect(self.saveImage)
        self.pushButton_6.clicked.connect(self.img_poisson_blend)
        self.pushButton_7.clicked.connect(self.take_pictures)
        self.pushButton_8.clicked.connect(self.alpha_blending_img)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "图像分割"))
        self.label.setText(_translate("MainWindow", "                                     图像分割及图像融合系统"))
        self.label_4.setText(_translate("MainWindow", "     original Image"))
        self.label_5.setText(_translate("MainWindow", "result Image"))
        self.pushButton.setText(_translate("MainWindow", "选择图片"))
        self.pushButton_2.setText(_translate("MainWindow", "运行时间"))
        self.pushButton_3.setText(_translate("MainWindow", "开始分割"))
        self.pushButton_4.setText(_translate("MainWindow", "grabCut"))
        self.pushButton_5.setText(_translate("MainWindow", "保   存"))
        self.pushButton_6.setText(_translate("MainWindow", "图像融合"))
        self.pushButton_7.setText(_translate("MainWindow", "拍摄图像"))
        self.pushButton_8.setText(_translate("MainWindow", "背景替换"))

    # 选择本地图片上传
    def openImage(self):
        global imgNamepath  # 这里为了方便别的地方引用图片路径,将其设置为全局变量
        # 弹出一个文件选择框,第一个返回值imgName记录选中的文件路径+文件名,第二个返回值imgType记录文件的类型
        # QFileDialog就是系统对话框的那个类第一个参数是上下文,第二个参数是弹框的名字,第三个参数是默认打开的路径,第四个参数是需要的格式
        imgNamepath, imgType = QFileDialog.getOpenFileName(self.centralwidget, "选择图片",
                                                           "D:\\python\\RRJ\\pycharmproject\\Practice\\chep2\\bdd2",
                                                           "*.jpg;;*.png;;All Files(*)")
        # 通过文件路径获取图片文件,并设置图片长宽为label控件的长、宽
        # img = QtGui.QPixmap(imgNamepath).scaled(self.label_2.width(), self.label_2.height())
        imgShow = QtGui.QPixmap(imgNamepath)
        self.label_2.setScaledContents(True)
        self.label_2.setPixmap(imgShow)
        # 显示所选图片的路径
        self.lineEdit.setText(imgNamepath)

    # 执行分割
    def start_paddle_Image(self):
        tstart = time.time()
        global flag
        flag = 1
        pdcut_img_path = paddle_Image.paddle_cut_Image(imgNamepath)
        pdcut_img = QPixmap(pdcut_img_path)
        self.label_3.setScaledContents(True)
        self.label_3.setPixmap(pdcut_img)
        tend = time.time()
        result = tend - tstart
        self.lineEdit_2.setText(str('%.3f' % float(result)) + 's')

    # grabCut_img
    def start_grabcut(self):
        tstart = time.time()
        global flag
        flag = 2
        gb_img_path = grabCut3.main(imgNamepath)
        # print(pdcut_img_path)
        gb_img = QPixmap(gb_img_path)
        self.label_3.setScaledContents(True)
        self.label_3.setPixmap(gb_img)
        tend = time.time()
        result = tend - tstart
        self.lineEdit_2.setText(str('%.3f' % float(result)) + 's')

    # 保存图片到本地(第二种方式:首先提取相对应Qlabel中的图片,然后打开一个保存文件的弹出框,最后保存图片到选中的路径)
    def saveImage(self):
        # 提取Qlabel中的图片
        img = self.label_3.pixmap().toImage()
        # print(type(img))
        fpath, ftype = QFileDialog.getSaveFileName(self.centralwidget, "保存图片", "d:\\", "*.png;;*.jpg;;All Files(*)")
        img.save(fpath)

    # 图像泊松融合
    def img_poisson_blend(self):
        tstart = time.time()
        self.openImage()
        if self.label_3.text() == "结果显示区":
            src_img = cv2.imread(imgNamepath)
        else:
            # 提取Qlabel中的图片
            src_img = self.label_3.pixmap().toImage()
            # 判断路径是否存在,如果不存在则新建
            path = "D:\\python\\RRJ\\pycharmproject\\Image_Segmentation\\PyQtImgZCQ\\"
            if not os.path.exists(path):
                os.mkdir(path)
            # 因为不知道怎么将转换为类型,因此采用暂存再读出的方式
            path = os.path.join(path, 'ZC.png')
            src_img.save(path)
            src_img = cv2.imread(path)
        # src_img = cv2.cvtColor(src_img,cv2.COLOR_RGB2BGR)
        poisson_img_path = poisson_blending.img_Poisson_Blending(src_img, imgNamepath)
        # pyqt5从路径读取图片
        imgShow = QPixmap(poisson_img_path)
        self.label_3.setScaledContents(True)
        self.label_3.setPixmap(imgShow)
        tend = time.time()
        result = tend - tstart
        self.lineEdit_2.setText(str('%.3f' % float(result)) + 's')

  
    # 拍摄照片
    def take_pictures(self):
        global imgNamepath
        imgNamepath = takephotos.take_photos()
        print(imgNamepath)
        show_take_img = QPixmap(imgNamepath)
        self.label_2.setScaledContents(True)
        self.label_2.setPixmap(show_take_img)

    # 背景替换
    def alpha_blending_img(self):
        tstart = time.time()
        self.openImage()
        fore_imgpath = ''
        if self.label_3.text() == "结果显示区":
            src_img = cv2.imread(imgNamepath)
        else:
            # 提取Qlabel中的图片
            src_img = self.label_3.pixmap().toImage()
            # 判断路径是否存在,如果不存在则新建
            path = "D:\\python\\RRJ\\pycharmproject\\Image_Segmentation\\PyQtImgZCQ\\"
            if not os.path.exists(path):
                os.mkdir(path)
            # 因为不知道怎么将转换为类型,因此采用暂存再读出的方式
            path = os.path.join(path, 'ZC.png')
            src_img.save(path)
            fore_imgpath = path
            # src_img = cv2.imread(path)
        Alpha_img_path = ''
        if flag == 1:
            Alpha_img_path = Alpha_Blending.alpha_blending(fore_imgpath, imgNamepath)
        if flag == 2:
            Alpha_img_path = Alpha_Blending.alpha_blending2(fore_imgpath, imgNamepath)
        # pyqt5从路径读取图片
        imgShow = QPixmap(Alpha_img_path)

        self.label_3.setScaledContents(True)
        self.label_3.setPixmap(imgShow)
        tend = time.time()
        result = tend - tstart
        self.lineEdit_2.setText(str('%.3f' % float(result)) + 's')

四、实验结果与分析

(1) 图像分割

                                                   图2-8 deeplabV3模型分割结果(1) 

                                               图2-9 grabCut分割结果(1)

 

                                          图2-10 deeplabV3模型分割结果(2) 

                                             图2-11 grabCut分割结果(2)

                                                 图2-12 deeplabV3模型分割结果(3) 

                                                  图2-13 grabCut分割结果(3)

 通过对比可以看到,deeplabV3模型的分割结果十分优秀,不论是单人还是多人图像,都可以得到很好的效果,几乎没有锯齿痕迹。grabCut分割结果在简单证件照的时候效果和deeplabV3模型效果近似相同,但是在具有复杂背景和多人的情况下分割锯齿痕迹明显,且有分割前景缺失现象,而且在某些情形下前景区域不好手动标定。在grabCut设置迭代次数20的时候二者在运行时间上都较慢,时间复杂度高。

(2)图像融合

                                                     图2-14 Poisson Blending结果 

利用OpenCV中的seamlessClone()函数实现,参数选择MIXED_CLONE,保留背景图像的细节,目标区域的梯度由原图像和背景图像组合计算得到,但是从结果来看是将两幅图像像素梯度计算进行了深度融合,不是单纯的背景替换,可以用于人物模糊等应用场景。

(3)背景替换(Alpha Blending

                                            图2-15 deeplabV3模型分割结果替换 

                                             图2-16  grabCut分割结果替换

总结

此次实验我实现利用opencv和百度开源库实现了图像分割与图像融合,对图割法有了更多了解,也体会了图割法在实际问题中的使用,grabCut是基本图割法的基础上增加迭代次数和高斯混合模型计算区域项,理论上迭代次数越多分割效果越好,是以牺牲时间复杂度来换取正确率,但是正式操作的时候需要人为标定前景区域,有容易出现误操作和前景难以准备标出的现象,导致分割结果不好。同时发现发现了语义分割领域一个十分优秀的模型deeplabV3,了解了它的基本理解,调用模型测试了分割结果确实相当优秀,主要问题是在cpu情况下运行相对较慢。在这次课设中我也学到了pyqt制作图形化界面的相关操作,也了解了更多Opencv中图像操作函数,但还存在一些不足,主要在于没有自己实现算法流程,缺乏对算法的深入理解,ui界面设置的不够流畅,无法避免实际应用中的误操作。

详细代码:github



推荐阅读
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 如何使用Python从工程图图像中提取底部的方法?
    本文介绍了使用Python从工程图图像中提取底部的方法。首先将输入图片转换为灰度图像,并进行高斯模糊和阈值处理。然后通过填充潜在的轮廓以及使用轮廓逼近和矩形核进行过滤,去除非矩形轮廓。最后通过查找轮廓并使用轮廓近似、宽高比和轮廓区域进行过滤,隔离所需的底部轮廓,并使用Numpy切片提取底部模板部分。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 使用Spring AOP实现切面编程的步骤和注意事项
    本文介绍了使用Spring AOP实现切面编程的步骤和注意事项。首先解释了@EnableAspectJAutoProxy、@Aspect、@Pointcut等注解的作用,并介绍了实现AOP功能的方法。然后详细介绍了创建切面、编写测试代码的过程,并展示了测试结果。接着讲解了关于环绕通知的使用方法,并修改了FirstTangent类以添加环绕通知方法。最后介绍了利用AOP拦截注解的方法,只需修改全局切入点即可实现。使用Spring AOP进行切面编程可以方便地实现对代码的增强和拦截。 ... [详细]
  • Python教学练习二Python1-12练习二一、判断季节用户输入月份,判断这个月是哪个季节?3,4,5月----春 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
author-avatar
潘巧军_837
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有