【CV作业02】图像灰度值变换+UI

目录

参考资料:

代码

1. 各种转换方法的实现

 2. UI 设计(这里只展示功能实现部分,自动生成的代码已省去)

3. 启动程序


参考资料:

PyQT6的从零开始(一):在Anaconda下安装PyQT6+在Pycharm中如何配置与使用-CSDN博客

数字图像处理之点运算---分段线性变换_jxqbuct的博客-CSDN博客

第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波4 - 分段线性变换 - 对比度拉伸_分段线性变换python_jasneik的博客-CSDN博客

PyQt5实现按键显示文件夹中图片_pyqt显示图像_木南成长之路的博客-CSDN博客

代码

1. 各种转换方法的实现

"""
该文件实现了1个计算个灰度值的像素个数函数
实现了5个转换函数(均保存并返回目标图片)
为了实现后续展示图片,下面每个变换函数都会将目标图像保存为 img/dst_img.png
"""


def histogram(img):
    """
    计算各灰度值的像素个数
    :param img: 原始灰度图
    :return: n:各灰度值的像素个数
    """
    H, W = img.shape[:2]
    n = np.zeros(256)
    # 循环遍历每个像素点
    for i in range(H):
        for j in range(W):
            n[img[i][j]] += 1
    return n


def histogram_equalization(img):
    """
    直方图均衡化
    :param img: 原始灰度图
    :return: 直方图均衡化后的图
    """
    H, W = img.shape[:2]
    # 计算直方图
    n = histogram(img)
    # 计算直方图频率
    p = n / (H*W)
    # 计算累计频率
    s = np.zeros(256)
    sum = 0
    for i in range(256):
        s[i] = p[i] + sum
        sum = s[i]
    # 计算输出灰度
    s = s * 255
    # 创建新图片
    dst_img = img.copy()
    for i in range(H):
        for j in range(W):
            dst_img[i, j] = s[img[i, j]]
    cv.imwrite('img/dst_img.png', dst_img)
    return dst_img


def gray_reverse(img):
    """
    灰度反转
    :param img: 原始灰度图
    :return: 灰度反转图
    """
    dst_img = np.array(255-img)      # 这里的 np.array 处理是为了防止 cv.imwrite 报错
    cv.imwrite('img/dst_img.png', dst_img)
    return dst_img


def linear_transform(img, x1, x2, y1, y2):
    """
    用 opencv 实现分段线性变换
    :return: 分段线性变换后的图
    """
    lut = np.zeros(256)
    for i in range(256):
        if i < x1:
            lut[i] = (y1 / x1) * i
        elif i < x2:
            lut[i] = ((y2 - y1) / (x2 - x1)) * (i - x1) + y1
        else:
            lut[i] = ((y2 - 255.0) / (x2 - 255.0)) * (i - 255.0) + 255.0
    dst_img = cv.LUT(img, lut)
    dst_img = np.uint8(dst_img + 0.5)  # +0.5有它自己的道理吧,但是效果看不出来
    cv.imwrite('img/dst_img.png', dst_img)
    return dst_img


def log_transform(img, c=1):
    """
    对数变换
    :param img: 原始灰度图
    :param c: 常数
    :return: 对数变换的图
    """
    s = c * np.log(1+img)
    # 不知道为什么c的取值不会影响最终的图片效果,可能和下面的缩放处理有关
    # 缩放
    sm = s - s.min()
    dst_img = (sm / sm.max()) * 255
    dst_img = np.uint8(dst_img + 0.5)
    cv.imwrite('img/dst_img.png', dst_img)
    return dst_img


def power_transform(img, c, gamma):
    """
    伽马变换
    :param img: 原始灰度图
    :param c: 常数
    :param gamma:常数,次方
    :return:伽马变换后的图
    """
    s = c * pow(img, gamma)
    # 缩放
    sm = s - s.min()
    dst_img = (sm / sm.max()) * 255
    dst_img = np.uint8(dst_img + 0.5)
    cv.imwrite('img/dst_img.png', dst_img)
    return dst_img

#     # 测试函数功能
# if __name__ == "__main__":
#     # 读入灰度图
#     org_img = cv.imread('img.png')
#     print(org_img.shape)
#     # 绘制直方图
#     n = histogram(org_img)
#     plt.bar(range(256), n)
#     plt.show()
#     # 灰度反转
#     rvs_img = gray_reverse(org_img)
#     # 直方图均衡化
#     equ_img = histogram_equalization(org_img)
#     histogram(equ_img)
#     # 线性变换
#     # 这里的参数可以调整,当前参数对课件上图片效果较好
#     lin_img = linear_transform(org_img, 50, 200, 80, 230)
#
#     log_img = log_transform(org_img)
#
#     pow_img = power_transform(org_img, 1, 0.4)
#     # 通过 imshow 显示图片
#     cv.imshow("origin_img", org_img)
#     cv.imshow("pow_img", pow_img)
#     cv.imshow("rvs_img", rvs_img)
#     cv.imshow("equ_img", equ_img)
#     cv.waitKey(0)

 2. UI 设计(这里只展示功能实现部分,自动生成的代码已省去)

"""
这里使用了PyQt6进行UI设计
使用了GTDesigner工具(可视化制作GUI)和pyUIC工具(将QTdesigner中生成的.ui文件转换为.py文件)
"""


# 保存直方图
def save_histogram(img, name):
    n = histogram(img)
    plt.bar(range(256), n)
    # 为了方便,这里的 name 其实只有两种:原图直方图和转换后直方图
    img_path = './img/{}.png'.format(name)
    plt.savefig(img_path)  # 保存直方图
    plt.cla()  # 清除之前的plt,否则会一直保留之前生成过的直方图
    return img_path  # 因为后面 QPixmap 需要用到图片地址


class Ui_Dialog(object):
    def __init__(self):
        self.org_img = None  # 保存选择的原始灰度图

    # 自动生成
    def setupUi(self, Dialog):
        # 省略

        # 设定按钮的功能
        self.button_connect()

    # 自动生成
    def retranslateUi(self, Dialog):
        # 省略

    # 给每个按钮加上点击功能
    def button_connect(self):
        self.pushButton.clicked.connect(self.open_img)
        self.pushButton_3.clicked.connect(lambda: self.show_dst_img(3))
        self.pushButton_4.clicked.connect(lambda: self.show_dst_img(4))
        self.pushButton_5.clicked.connect(lambda: self.show_dst_img(5))
        self.pushButton_6.clicked.connect(lambda: self.show_dst_img(6))
        self.pushButton_7.clicked.connect(lambda: self.show_dst_img(7))

    # 打开图片
    def open_img(self):
        imgName, imgType = QFileDialog.getOpenFileName(None, "打开图片", "lab02/img/", "*.png;;*.jpg;;All Files(*)")
        self.org_img = cv.imread(imgName)
        # 显示图片
        pix = QPixmap(imgName).scaled(self.label_5.width(), self.label_5.height())
        self.label_5.setPixmap(pix)
        # 显示直方图
        his_imgName = save_histogram(self.org_img, '原图直方图')
        pix = QPixmap(his_imgName).scaled(self.label_3.width(), self.label_3.height())
        self.label_3.setPixmap(pix)

    # 显示转换后的图片及直方图
    def show_dst_img(self, x):
        if x == 3:
            gray_reverse(self.org_img)
        elif x == 4:
            histogram_equalization(self.org_img)
        elif x == 5:
            # 由于 ui 没有设计可以传递参数的入口,这里使用固定参数
            linear_transform(self.org_img, 50, 200, 80, 230)
        elif x == 6:
            # 由于 ui 没有设计可以传递参数的入口,这里使用固定参数
            power_transform(self.org_img, 1, 0.4)
        elif x == 7:
            log_transform(self.org_img)
        dst_img = cv.imread('img/dst_img.png')
        # 显示图片
        pix = QPixmap('img/dst_img.png').scaled(self.label_6.width(), self.label_6.height())
        self.label_6.setPixmap(pix)
        # 显示直方图
        his_imgName = save_histogram(dst_img, '转换后直方图')
        pix = QPixmap(his_imgName).scaled(self.label_4.width(), self.label_4.height())
        self.label_4.setPixmap(pix)

3. 启动程序

if __name__ == '__main__':

    # 创建ui,引用 Ui_MainWindow类
    app = QApplication(sys.argv)
    mainWindow = QMainWindow()
    ui = ui_sys.Ui_Dialog()
    # 调用 setupUi,创建初始组件
    ui.setupUi(mainWindow)
    # 创建窗口
    mainWindow.show()
    # 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)
    sys.exit(app.exec())

注:

第一次接触pyqt,效果可能实现了但是代码质量不一定高

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值