python实现半色调技术图像转换

半色调技术

半色调技术是一种将灰度图像转换为黑白图像的技术。它是通过将灰度图像的像素值映射到黑白像素值上来实现的。

比如说,在一块只能显示纯黑或纯白的屏幕上,如何将一张灰度图显示出灰度的效果,这时就可以用半色调技术实现。

如下,左边是一张灰度图,中间是使用半色调技术转换后输出的图像,右边是输出图像的局部放大

初始灰度图半色调转换后的输出图像输出图像局部放大(使用win10自带【画图】软件打开放大)
image-20230307153806255b_timage-20230307154005805

原理

基本原理

我们都知道,一个像素点有0~255共256种灰度值,值越大图像越“白”,反之越“黑”。

对于一些屏幕,只能显示0或1(用1表示255)两种灰度值,也就是只能显示纯黑或纯白,这怎么办?

半色调技术实际是把一个像素点用一个矩阵块来表示,如果像素值比较大(越白),那么矩阵快白色部分就越多,如图所示:

image-20230307160532625

这个矩阵就是bayer矩阵,矩阵边长可以选择1,2,4,8,16,上图矩阵边长是2

如果是16,那么就可以表示16*16=256种灰度值了

如上图所示,对于边长为2的bayer矩阵,假如只有4种颜色值(0,1,2,3),如果像素值比0大,那么就把bayer矩阵的位置0设置为白色;如果比1大,就把位置0和1都设置为白色……

但实际上,灰度值有256种,因此bayer矩阵需要乘以(256/(2*2)),如下

image-20230307162219466

如果像素值比128大,那么0,64,128这3个位置都设置为白色

可以看出,假设输入图像边长为a,bayer矩阵边长为k,则输出图像的边长为a*k,即是输入图像的k倍

bayer矩阵生成

img

注意:整数*矩阵即矩阵的数乘运算,相当于矩阵每个元素都乘以一个整数

根据这个公式,可以写出一个代码:

def getStandardMat(k):
    '''
    函数作用:获取bayer矩阵
    return:是否生成成功,成功的话同时返回numpy类型的矩阵
    k: 是bayer矩阵的阶数,取值一般为1 2 4 8 16
    '''
    if k & (k-1) != 0:
        return False, None
    if k == 1:
        return True, [[0.5]]
    m = [[0, 2], [3, 1]]
    m = np.array(m)
    while(m.shape[0] != k):
        m1 = np.zeros((m.shape[0]*2, m.shape[1]*2))
        m1[:m.shape[0], :m.shape[1]] += 4*m
        m1[:m.shape[0], m.shape[1]:] += 4*m+2
        m1[m.shape[0]:, :m.shape[1]] += 4*m+3
        m1[m.shape[0]:, m.shape[1]:] += 4*m+1
        m = m1
    return True, m

测试一下:

image-20230307163826329image-20230307163903989image-20230307163929791

实践操作

该程序实现读取一张RGB图片,转为灰度图后再采用变色调技术转换图片

使用该程序只需要修改输入图片路径以及输出图片路径即可

# 该文件实现半色调技术的代码

import cv2
import numpy as np

def getBayerMat(k):
    '''
    函数作用:获取bayer矩阵
    return:是否生成成功,成功的话同时返回numpy类型的矩阵
    k: 是bayer矩阵的阶数,取值一般为1 2 4 8 16
    '''
    if k & (k-1) != 0:
        return False, None
    if k == 1:
        return True, np.array([[0.5]])
    m = [[0, 2], [3, 1]]
    m = np.array(m)
    while(m.shape[0] != k):
        m1 = np.zeros((m.shape[0]*2, m.shape[1]*2))
        m1[:m.shape[0], :m.shape[1]] += 4*m
        m1[:m.shape[0], m.shape[1]:] += 4*m+2
        m1[m.shape[0]:, :m.shape[1]] += 4*m+3
        m1[m.shape[0]:, m.shape[1]:] += 4*m+1
        m = m1
    return True, m


def convertImg(img, k=4, f=False, useGray=False):
    '''
    k:bayer矩阵大小
    f:由于转换后图像尺寸会变大k倍,f表示是否先缩小k倍
    useGray:传入的img是否为灰度图
    '''
    if not useGray:
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    if f:
        img = cv2.resize(img, dsize=None, fx=1/k, fy=1/k)
    ret, bayers = getBayerMat(k)
    if not ret:
        print(f"矩阵阶数k={k}非2的倍数")
        return

    bayers *= (256//(k*k))
    h, w = img.shape
    newImg = np.zeros((k*h, k*w), dtype='uint8')
    
    # 遍历图像每个像素点
    for i in range(0, h, 1):
        for j in range(0, w, 1):
            # 对于每个像素点,遍历bayer矩阵,判断是否该把矩阵中某一位置设置为纯白(255)或纯黑(0)
            for p in range(k): 
                for q in range(k):
                    if img[i][j] > bayers[p][q]:
                        newImg[k*(i)+p][k*(j)+q] = 255
                    else:
                        newImg[k*(i)+p][k*(j)+q] = 0
    return newImg

if __name__ == '__main__':
    imgPath = r'D:\Users\xxx\Desktop\imgs\1-1.jpg'
    img = cv2.imread(imgPath, 0)  # 读取图片并转为灰度图
    nimg = convertImg(img, k=4, f=False, useGray=True)
    cv2.imwrite("../out/b2.png", nimg) # 输出转换后的图片


使用pyqt5做一个GUI操作界面

▶代码下载

需要安装的库

PyQt5                             5.15.0
opencv-python                     4.3.0.36
numpy                             1.19.0

image-20230307170508261

使用方法:

运行src/main.py文件即可

> python main.py

image-20230308104334962

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
色调是一种图像处理技术,它可以将连续的灰度图像转换为只包含黑色和白色点的二值图像。在色调过程中,将图像分割成小的块,然后在每个块内根据灰度值密度分布的规律,用黑色和白色的点来表示不同的灰度等级。色调可以使得图像在黑白之间产生渐变,从而达到更好的视觉效果。 对于色调整背景色,可以在色调处理的过程中,将背景色所在的像素点设置为白色或黑色,从而改变背景色。一些色调算法中,还可以通过整点的大小、密度、形状等参数来进一步整背景色。 以下是一个简单的 C++ 实现示例: ```c++ #include <opencv2/opencv.hpp> using namespace cv; void halfToning(Mat& src, Mat& dst, int bgValue) { int threshold = 128; int width = src.cols; int height = src.rows; int x, y; uchar grayValue; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grayValue = src.at<uchar>(y, x); if (grayValue > threshold) { if (grayValue == bgValue) { dst.at<uchar>(y * 2, x * 2) = 0; dst.at<uchar>(y * 2, x * 2 + 1) = 0; dst.at<uchar>(y * 2 + 1, x * 2) = 0; dst.at<uchar>(y * 2 + 1, x * 2 + 1) = 0; } else { dst.at<uchar>(y * 2, x * 2) = 255; dst.at<uchar>(y * 2, x * 2 + 1) = 255; dst.at<uchar>(y * 2 + 1, x * 2) = 255; dst.at<uchar>(y * 2 + 1, x * 2 + 1) = 255; } } else { if (grayValue == bgValue) { dst.at<uchar>(y * 2, x * 2) = 255; dst.at<uchar>(y * 2, x * 2 + 1) = 255; dst.at<uchar>(y * 2 + 1, x * 2) = 255; dst.at<uchar>(y * 2 + 1, x * 2 + 1) = 255; } else { dst.at<uchar>(y * 2, x * 2) = 0; dst.at<uchar>(y * 2, x * 2 + 1) = 0; dst.at<uchar>(y * 2 + 1, x * 2) = 0; dst.at<uchar>(y * 2 + 1, x * 2 + 1) = 0; } } } } } int main() { Mat src = imread("input.jpg", IMREAD_GRAYSCALE); Mat dst(src.rows * 2, src.cols * 2, CV_8UC1, Scalar(0)); halfToning(src, dst, 255); // 将白色背景整为黑色 imshow("Half Toning", dst); waitKey(0); return 0; } ``` 该示例中,我们使用 OpenCV 库来读取灰度图像并进行色调处理。`halfToning` 函数中,我们将输入的灰度图像 `src` 进行色调处理,并将结果保存在输出图像 `dst` 中。在色调处理中,我们使用一个阈值 `threshold` 来将灰度值进行分割,并根据分割后的结果进行色调处理。在处理过程中,如果当前像素点的灰度值与背景色相同,则将其设置为黑色或白色。最终,我们展示了处理后的图像并等待用户按下任意键退出程序。 需要注意的是,该示例只是一个简单的示例,实际应用中可能需要更加复杂的算法或者处理逻辑。同时,该示例中使用的是将白色背景整为黑色的方法,如果您需要整其他颜色的背景,可以根据具体情况进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

[小G]

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值