基于QT与CV的图像增强软件:十几种图像增强方式

内容摘要

  • 如下图所示,这个软件实现了对单张图片常用的12种图像增强方式。翻转、随机旋转、随机缩放、平移、随机裁剪、加入噪声(随机噪声,高斯噪声,椒盐噪声)、改变对比度、饱和度、亮度、可以使用直方图增强、转为灰度图、随机擦除等12中方式。
  • 其他的增强方式可根据需要拓展

在这里插入图片描述

  • 还支持多种增强方式组合在一起

在这里插入图片描述

  • 还有优化空间,部分功能未完善!

实现过程

1. 知识储备

  • python编程
  • pyside6,or pyqt5
  • cv2

2.图像增强的概念

3. 代码

  • OK,直接上代码讲解
  • 主要就是两部分,UI界面设计,图像增强实现,最后两个和一起

UI界面代码

import sys
import cv2
import numpy as np
from PySide6.QtWidgets import QMainWindow, QApplication, QFileDialog
from PySide6.QtGui import QPixmap,QImage

from data_argument_ui import Ui_MainWindow
from image_processing import ImageProcessor

def convert_cv2_to_pixmap(cv2_image):
    # 将cv2导出的图像转换为QImage
    cv2_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
    height, width, channel = cv2_image.shape
    bytesPerLine = 3 * width
    qImg = QImage(cv2_image.data, width, height, bytesPerLine, QImage.Format_RGB888)

    # 使用QPixmap将QImage转换为可在界面中显示的格式
    pixmap = QPixmap.fromImage(qImg)

    return pixmap


class MainWindow(QMainWindow, Ui_MainWindow,ImageProcessor):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)      

        self.textBrowser.ensureCursorVisible() # 使得文本自动换行

        # 按键关联
        self.bind_slots()


    # -----按钮函数--start-----#
    def open_image(self):
        self.to_ui("打开图片")
        file_path = QFileDialog.getOpenFileName(self, dir="", filter="*.jpg;*.png;*.jpeg")
        if file_path:
            self.path = file_path[0] # 不能少这一句
            self.in0.setPixmap(QPixmap.fromImage(QImage(self.path)))
            # 数据增强
            self.renew()
    def renew(self):
        # -----数据增强处理--start-----#
        # X轴翻转
        image = self.cv_xflipping(self.path)
        self.in1.setPixmap(convert_cv2_to_pixmap(image))
        name = "result/ " +"1100003"+ "_01" +".jpg"
        cv2.imwrite(name, image)
        # 随机旋转
        image,angle= self.cv_rotation(self.path)
        name = "result/ " +"1100003"+ "_02" +".jpg"
        cv2.imwrite(name, image)
        print(f"随机角度: {round(angle,2)} ℃")
        self.in2.setPixmap(convert_cv2_to_pixmap(image))
        # 随机缩放
        image,scale_percent = self.cv_scaling(self.path)
        name = "result/ " +"1100003"+ "_03" +".jpg"
        cv2.imwrite(name, image)
        print(f"缩放比例 {round(scale_percent/100,2)} ")
        self.in3.setPixmap(convert_cv2_to_pixmap(image))
        # 平移
        image = self.cv_translation(self.path) #
        name = "result/ " +"1100003"+ "_04" +".jpg"
        cv2.imwrite(name, image)
        self.in4.setPixmap(convert_cv2_to_pixmap(image))

        # 裁剪
        image = self.cv_cropping(self.path,150,150) # 
        name = "result/ " +"1100003"+ "_05" +".jpg"
        cv2.imwrite(name, image)
        self.in5.setPixmap(convert_cv2_to_pixmap(image))

                # 6 加入噪声,可选随机噪声,如高斯噪声、椒盐噪声
        image = self.cv_noise(self.path,'gaussian') # 
        name = "result/ " +"1100003"+ "_06" +".jpg"
        cv2.imwrite(name, image)
        self.in6.setPixmap(convert_cv2_to_pixmap(image))

                # 改变对比度
        image = self.cv_Contrast(self.path) #
        name = "result/ " +"1100003"+ "_07" +".jpg"
        cv2.imwrite(name, image)
        self.in7.setPixmap(convert_cv2_to_pixmap(image))

                # 改变饱和度
        image = self.cv_Saturation(self.path) #
        name = "result/ " +"1100003"+ "_08" +".jpg"
        cv2.imwrite(name, image)
        self.in8.setPixmap(convert_cv2_to_pixmap(image))

                # 改变亮度
        image = self.cv_Light(self.path) # 
        name = "result/ " +"1100003"+ "_09" +".jpg"
        cv2.imwrite(name, image)
        self.in9.setPixmap(convert_cv2_to_pixmap(image))

                # 直方图增强
        image = self.cv_histogram(self.path) # 
        name = "result/ " +"1100003"+ "_10" +".jpg"
        cv2.imwrite(name, image)
        self.in10.setPixmap(convert_cv2_to_pixmap(image))

                # 灰度图
        image = self.cv_gray(self.path) # 
        name = "result/ " +"1100003"+ "_11" +".jpg"
        cv2.imwrite(name, image)
        self.in11.setPixmap(convert_cv2_to_pixmap(image))

                # 随机擦除
        image = self.cv_reasing(self.path) # 
        name = "result/ " +"1100003"+ "_12" +".jpg"
        cv2.imwrite(name, image)
        self.in12.setPixmap(convert_cv2_to_pixmap(image))
        # -----数据增强处理--end-----#


    def check(self):
        pass
    def saveAll(self):
        pass
    # -----按钮函数--end-----#

    def func(self):
        print(self)
        # print(self.rotate.isChecked())
    def checkOK(self):
        pass
        # 检测那个按钮被按下
        # print(self.V3buttonGroup.checkedButton().text())
        # print(self.rotate.isChecked())
    def V1(self):
        if self.xflipping.isChecked():
            print("X 翻转")
        if self.rotation.isChecked():
            print("随机旋转")
        if self.scaling.isChecked():
            print("3")
        if self.translation.isChecked():
            print("4")
        if self.cropping.isChecked():
            print("5")
        if self.noise.isChecked():
            print("6")
        if self.Contrast.isChecked():
            print("7")
        if self.Saturation.isChecked():
            print("8")
        if self.Light.isChecked():
            print("9")
        if self.histogram.isChecked():
            image = self.cv_histogram(self.path) # 
        if self.gray.isChecked():
            image = self.cv_gray(self.path) # 
        if self.reasing.isChecked():
            image = self.cv_reasing(self.path) # 
        
        
        self.in13.setPixmap(convert_cv2_to_pixmap(image))

    # -----其他-------#
    def to_ui(self,str):
        out= str
        self.textBrowser.append(out)

    def bind_slots(self):
        # -----按钮-------#
        self.picture.clicked.connect(self.open_image)
        self.reLoad.clicked.connect(self.renew)
        self.check.clicked.connect(self.checkOK)
        self.save.clicked.connect(self.saveAll)
        

        # -----其他-------#
        self.buttonGroup.buttonClicked.connect(self.V1)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    # print(11)
    window = MainWindow()
    window.show()
    
    app.exec()

图像增强代码

import cv2
import numpy as np
import random
from random import randint

class ImageProcessor:
    def __init__(self):
        pass

    def cv_xflipping(self, image_path):
        image = cv2.imread(image_path)
        flipped_image = cv2.flip(image, 1)
        return flipped_image

    
    def cv_rotation(self, image_path):
        # 读取图片
        image = cv2.imread(image_path)
        # 生成随机角度
        angle = random.uniform(-20, 20)
        # 获取图像尺寸
        height, width = image.shape[:2]
        center = (width / 2, height / 2)
        # 旋转矩阵
        rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
        # 执行旋转
        rotated_image = cv2.warpAffine(image, rotation_matrix, (width, height), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))
        return rotated_image , angle
    
    def cv_scaling(self,image_path):
        # 读取图片
        image = cv2.imread(image_path)
        scale_percent = randint(80,99)
        # 获取图像尺寸
        width = int(image.shape[1] * scale_percent / 100)
        height = int(image.shape[0] * scale_percent / 100)
        dim = (width, height)

        # 执行缩放
        resized_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)

        # 创建空白画布
        new_image = np.ones((height, width, 3), dtype=np.uint8) * 255

        # 将缩放后的图片放置在新画布上
        x_offset = (new_image.shape[1] - resized_image.shape[1]) // 2
        y_offset = (new_image.shape[0] - resized_image.shape[0]) // 2
        new_image[y_offset:y_offset+resized_image.shape[0], x_offset:x_offset+resized_image.shape[1]] = resized_image

        return new_image ,scale_percent
    
    def cv_translation(self,image_path):
        # 读取图片
        image = cv2.imread(image_path)
        tx, ty = randint(-20,20), randint(-20,20)
        # 构建平移矩阵
        M = np.float32([[1, 0, tx], [0, 1, ty]])

        # 执行平移
        translated_image = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]), borderValue=(255, 255, 255))

        return translated_image


    def cv_cropping(self,image_path, crop_width, crop_height):
        # 读取图片
        image = cv2.imread(image_path)

        # 获取图片的宽度和高度
        image_height, image_width = image.shape[:2]

        # 生成随机裁剪的起始点
        start_x = random.randint(0, image_width - crop_width)
        start_y = random.randint(0, image_height - crop_height)

        # 执行裁剪
        cropped_image = image[start_y:start_y+crop_height, start_x:start_x+crop_width]

        # 创建白色背景
        white_background = np.ones((crop_height, crop_width, 3), np.uint8) * 255

        # 将裁剪的部分放到白色背景中
        white_background[0:cropped_image.shape[0], 0:cropped_image.shape[1]] = cropped_image

        return white_background
    


    def cv_noise(self, image_path, noise_type):
        # 读取图片
        image = cv2.imread(image_path)

        # 添加随机噪声
        if noise_type == 'random':
            noise = np.random.rand(*image.shape) * 255
            noisy_image = cv2.addWeighted(image, 0.9, noise, 0.1, 0)
        # 添加高斯噪声
        elif noise_type == 'gaussian':
            mean = 0
            std_dev = 10
            noise = np.random.normal(mean, std_dev, image.shape)
            noisy_image = cv2.add(image, noise.astype(np.uint8))
        # 添加椒盐噪声
        elif noise_type == 'salt_pepper':
            noisy_image = image.copy()
            salt_vs_pepper = 0.5
            num_salt = np.ceil(salt_vs_pepper * image.size * 0.5)
            coords = [np.random.randint(0, i - 1, int(num_salt)) for i in image.shape]
            noisy_image[coords] = 1
            num_pepper = np.ceil(salt_vs_pepper * image.size * 0.5)
            coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in image.shape]
            noisy_image[coords] = 0
        else:
            raise ValueError("不支持的噪声类型")

        return noisy_image.astype(np.uint8)

    def cv_Contrast(self,image_path):
        # alpha 是对比度调整参数,它控制图像的白色和黑色之间的对比度。当 alpha 大于 1 时,对比度增加;当 alpha 小于 1 时,对比度减小。
        # beta 是亮度调整参数,它控制整个图像的亮度。当 beta 大于 0 时,图像变亮;当 beta 小于 0 时,图像变暗。
        # 读取图片
        img = cv2.imread(image_path)
        alpha = random.uniform(0.7,1.3)
        # 调整对比度和亮度
        adjusted_img = cv2.convertScaleAbs(img, alpha=alpha)

        return adjusted_img


    def cv_Saturation(self, image_path):
        # 读取图片
        img = cv2.imread(image_path)
        saturation_factor = random.uniform(0,2)
        # 将图片转换为HSV颜色空间
        hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

        # 调整饱和度
        h, s, v = cv2.split(hsv_img)
        s = np.clip(s * saturation_factor, 0, 255).astype(np.uint8)
        adjusted_hsv_img = cv2.merge([h, s, v])

        # 将调整后的图片转换回BGR颜色空间
        adjusted_img = cv2.cvtColor(adjusted_hsv_img, cv2.COLOR_HSV2BGR)

        return adjusted_img

    def cv_Light(self,image_path):
        # alpha 是对比度调整参数,它控制图像的白色和黑色之间的对比度。当 alpha 大于 1 时,对比度增加;当 alpha 小于 1 时,对比度减小。
        # beta 是亮度调整参数,它控制整个图像的亮度。当 beta 大于 0 时,图像变亮;当 beta 小于 0 时,图像变暗。
        # 读取图片
        img = cv2.imread(image_path)
        beta = random.uniform(-30,30)
        # 调整对比度和亮度
        adjusted_img = cv2.convertScaleAbs(img,  beta=beta)

        return adjusted_img

    def cv_histogram(self, image_path):
        # 彩色图 好像不能做直方图增强
        # 读取彩色图片
        img = cv2.imread(image_path)

        # 将彩色图片转换为YUV颜色空间
        img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)

        # 对Y通道进行直方图均衡化
        img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])

        # 将增强后的YUV图片转换回BGR颜色空间
        img_output = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)
        return img_output
    
    def cv_gray(self, image_path):
        # 读取彩色图片
        img = cv2.imread(image_path)

        # 将彩色图片转换为灰度图
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        return gray_img
    
    def cv_reasing(self, image_path):
        # 读取彩色图片
        img = cv2.imread(image_path)

        # 获取图片的高度和宽度
        height, width, _ = img.shape

        # 随机生成擦除框的起始点和大小
        x = np.random.randint(0, width - 50)
        y = np.random.randint(0, height - 50)
        w = np.random.randint(50, 100)
        h = np.random.randint(50, 100)

        # 在图片上随机擦除
        img[y:y+h, x:x+w] = np.random.randint(0, 256)

        return img


# 使用示例
if __name__ == "__main__":
    # 创建ImageProcessor对象,传入图像路径
    processor = ImageProcessor()
    img = cv2.imread('1100003.jpg')
    cv2.imshow('original', img)
    # 对图像进行X轴翻转
    image= processor.cv_reasing('1100003.jpg')
    # 显示翻转后的图像
    cv2.imshow('output', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

4 工程

工程链接,免费下载

总结

还有需要完善的地方,交流联系:QQ 1727359387

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值