热门标签 | 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



推荐阅读
  • 探索CNN的可视化技术
    神经网络的可视化在理论学习与实践应用中扮演着至关重要的角色。本文深入探讨了三种有效的CNN(卷积神经网络)可视化方法,旨在帮助读者更好地理解和优化模型。 ... [详细]
  • 构建Python自助式数据查询系统
    在现代数据密集型环境中,业务团队频繁需要从数据库中提取特定信息。为了提高效率并减少IT部门的工作负担,本文探讨了一种利用Python语言实现的自助数据查询工具的设计与实现。 ... [详细]
  • Java连接MySQL数据库的方法及测试示例
    本文详细介绍了如何安装MySQL数据库,并通过Java编程语言实现与MySQL数据库的连接,包括环境搭建、数据库创建以及简单的查询操作。 ... [详细]
  • 本文详细介绍了Spring AOP注解的基本概念及其实现方式,并通过实例演示了如何在项目中使用这些注解进行面向切面的编程。旨在帮助开发者更好地理解和运用Spring AOP功能。 ... [详细]
  • 本文探讨了Java中有效停止线程的多种方法,包括使用标志位、中断机制及处理阻塞I/O操作等,旨在帮助开发者避免使用已废弃的危险方法,确保线程安全和程序稳定性。 ... [详细]
  • 本文介绍了进程的基本概念及其在操作系统中的重要性,探讨了进程与程序的区别,以及如何通过多进程实现并发和并行。文章还详细讲解了Python中的multiprocessing模块,包括Process类的使用方法、进程间的同步与异步调用、阻塞与非阻塞操作,并通过实例演示了进程池的应用。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • selenium通过JS语法操作页面元素
    做过web测试的小伙伴们都知道,web元素现在很多是JS写的,那么既然是JS写的,可以通过JS语言去操作页面,来帮助我们操作一些selenium不能覆盖的功能。问题来了我们能否通过 ... [详细]
  • 择要:Fundebug的JavaScript毛病监控插件同步支撑Vue.js异步毛病监控。Vue.js从降生至今已5年,尤大在本年2月份宣布了严重更新,即Vue2.6。更新包含新增 ... [详细]
  • 本文介绍了一个基本的同步Socket程序,演示了如何实现客户端与服务器之间的简单消息传递。此外,文章还概述了Socket的基本工作流程,并计划在未来探讨同步与异步Socket的区别。 ... [详细]
  • 使用jQuery与百度地图API实现地址转经纬度功能
    本文详细介绍了如何利用jQuery和百度地图API将地址转换为经纬度,包括申请API密钥、页面构建及核心代码实现。 ... [详细]
  • 本文由公众号【数智物语】(ID: decision_engine)发布,关注获取更多干货。文章探讨了从数据收集到清洗、建模及可视化的全过程,介绍了41款实用工具,旨在帮助数据科学家和分析师提升工作效率。 ... [详细]
  • STM32代码编写STM32端不需要写关于连接MQTT服务器的代码,连接的工作交给ESP8266来做,STM32只需要通过串口接收和发送数据,间接的与服务器交互。串口三配置串口一已 ... [详细]
  • 本文将详细探讨 Python 编程语言中 sys.argv 的使用方法及其重要性。通过实际案例,我们将了解如何在命令行环境中传递参数给 Python 脚本,并分析这些参数是如何被处理和使用的。 ... [详细]
  • 近期尝试从www.hub.sciverse.com网站通过编程手段获取数据时遇到问题,起初尝试使用WebBrowser控件进行数据抓取,但发现使用GET方法翻页时,返回的HTML代码始终相同。进一步探究后了解到,该网站的数据是通过Ajax异步加载的,可通过HTTP查看详细的JSON响应。 ... [详细]
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社区 版权所有