Python + Opencv进行图片色彩分析

目录

 

问题背景

实现效果

代码思路及实现

小结


问题背景

前段时间遇到了一个需要进行色彩分析的项目,主要是针对文件夹内的照片进行HSV的分析,在网上寻找了一下资料,没看到什么这一方面的代码,于是记录一下实现过程

实现效果

代码主要运用到的Python和Opencv以及Matlab的库,绘制图片HSV的直方图,并对主要含有色彩进行占比分析,输出具体值并可视化

代码思路及实现

首先需要导入以下库

import os
import cv2 as cv
import matplotlib.pyplot as plt
from collections import Counter

使用os库的命令实现批量读取文件夹内的照片

def getfiles():
    file_path = '/Users/fbz/Desktop/City_Color/Photos'  # 文件夹路径
    file_names = os.listdir(file_path)
    print(file_names)
    return file_names, file_path

将图像格式从BGR转到HSV空间,对HSV的值统计绘制HSV直方图,并计算均值

def calchist_for_rgb(frame, num):
    h, s, v = cv.split(frame)  # 分离hsv三个通道
    hsv_H = cv.calcHist([h], [0], None, [256], [0, 255])
    hsv_S = cv.calcHist([s], [0], None, [256], [0, 255])
    hsv_V = cv.calcHist([v], [0], None, [256], [0, 255])

    # 绘制并保存色彩直方图
    plt.plot(hsv_H, color="r")
    plt.plot(hsv_S, color="g")
    plt.plot(hsv_V, color="b")
    plt.savefig("result_hsv" + str(num) + ".jpg")
    plt.show()
    # ---------------- hsv均值 -----------------------
    hsv_sum = 0
    h_c, h_r = h.shape
    for i in range(h_c):
        for j in range(h_r):
            hsv_sum = hsv_sum + h[i][j]
    hsv_sum = hsv_sum / (h_c * h_r)
    print('mean h =', hsv_sum)

    hsv_sum = 0
    s_c, s_r = s.shape
    for i in range(s_c):
        for j in range(s_r):
            hsv_sum = hsv_sum + s[i][j]
    hsv_sum = hsv_sum / (s_c * s_r)
    print('mean s =', hsv_sum)

    hsv_sum = 0
    v_c, v_r = v.shape
    for i in range(v_c):
        for j in range(v_r):
            hsv_sum = hsv_sum + v[i][j]
    hsv_sum = hsv_sum / (v_c * v_r)
    print('mean v =', hsv_sum)

直方图绘制完之后,我们就对图像的HSV空间分布有一个大体的了解了,但是要直观具体地了解一张图片的色彩占比,光直方图是远远不够的。我们还需要确定出一张图像的主要色彩以及各个主要色彩的占比,才能使数据有具体的作用。

那么就可以细分出两个小问题,第一个是如何从整个图像中区分出主要的颜色,第二个就是如何计算主要颜色的占比。

第一个问题的解决思路就是,遍历图像后统计像素值,提取出重复次数多的像素值,对这些像素值再进行一个区分统计,来划分出几个主要的色彩区间。这里采取的区分方法就是对三通道的差值计算均方根计算,小于阈值则说明区分度不够,大于一定的区分度阈值才能确定其色彩与另一色彩不同。

第二个问题就相对简单很多,只要统计出上述各色彩区间的色彩数量就可以了。

# 色彩占比分析
def color_sort(frame, num):
    c = []
    for x in range(frame.shape[0]):
        for y in range(frame.shape[1]):
            c.append(str(frame[x, y][0]) + ',' + str(frame[x, y][1]) + ',' + str(frame[x, y][2]))  # 遍历图片所有bgr值
    temp = Counter(c)
    most = temp.most_common(500)  # 按重复次数排序,抽取排在前500的元素
    count = 1  # 状态值,记录是否是第一个被加入的元素,1代表是
    color = []  # 储存主色彩
    color_num = []  # 储存各主色彩的数量
    for i in most:
        b_i, g_i, r_i = i[0].split(',')  # 待加入色彩
        if count == 1:
            # 第一个被加入的色彩
            color.append(str(b_i) + ',' + str(g_i) + ',' + str(r_i))
            count = 0
            color_num.append(1)
        state = False  # 状态量,若变更为Ture为新颜色,决定加入color内
        for j in color:
            b_o, g_o, r_o = j.split(',')  # 已加入色彩
            # 计算待加入色彩和已加入色彩的区分度,若过为区分度超过阈值则视为要加入的新色彩
            dis = (int(b_o) - int(b_i)) ** 2 + (int(g_o) - int(g_i)) ** 2 + (int(r_o) - int(r_i)) ** 2
            if dis <= threshold:  # 区分度过小,视为列表内已经存在该色彩
                color_num[color.index(j)] += 1
                break
            else:
                state = True  # 修改状态量加入新色彩
            if state and j == color[len(color) - 1]:  # 若所有已有颜色都遍历后state仍为True则加入该色彩
                color.append(str(b_i) + ',' + str(g_i) + ',' + str(r_i))
                color_num.append(1)

到此为止,所需的数据已经基本获得到了,但光是数据仍然不够直观,还差一步画图,画饼图或直方图的话感觉和图片关联度不大,于是打算将色彩分布图和原图放在同一个窗口内,直观简洁。

def color_draw(frame, color, color_num, num):
    start = 0
    Height = frame.shape[0]
    Width = frame.shape[1]
    image = cv.resize(frame, (Width, int(Height * 1.125)))  # 创建新画布
    image[0:Height, 0:Width] = frame  # 在新画布上部分填充原图像
    for i in range(len(color)):
        # 遍历所有主色彩,
        print(color[i])
        print(float(color_num[i] / 5), '%')  # 计算百分比,因抽取500个颜色故此处除5便可计算百分比
        b, g, r = color[i].split(',')
        f = int(color_num[i]) * Width / 500  # 计算当前色彩应在画布上的宽度
        image[Height:int(Height * 1.125), start:start + int(f)] = [b, g, r]  # 上色
        start = start + int(f)
    image = cv.cvtColor(image, cv.COLOR_HSV2BGR)
    cv.imshow('result' + str(num), image)
    cv.imwrite('result' + str(num) + '.jpg', image)
    cv.waitKey(0)

小结

完整代码如下

import os
import cv2 as cv
import matplotlib.pyplot as plt
from collections import Counter

threshold = 80  # 区分度阈值


# 计算彩色图的直方图
def calchist_for_rgb(frame, num):
    h, s, v = cv.split(frame)  # 分离hsv三个通道
    hsv_H = cv.calcHist([h], [0], None, [256], [0, 255])
    hsv_S = cv.calcHist([s], [0], None, [256], [0, 255])
    hsv_V = cv.calcHist([v], [0], None, [256], [0, 255])

    # 绘制并保存色彩直方图
    plt.plot(hsv_H, color="r")
    plt.plot(hsv_S, color="g")
    plt.plot(hsv_V, color="b")
    plt.savefig("result_hsv" + str(num) + ".jpg")
    plt.show()
    # ---------------- hsv均值 -----------------------
    hsv_sum = 0
    h_c, h_r = h.shape
    for i in range(h_c):
        for j in range(h_r):
            hsv_sum = hsv_sum + h[i][j]
    hsv_sum = hsv_sum / (h_c * h_r)
    print('mean h =', hsv_sum)

    hsv_sum = 0
    s_c, s_r = s.shape
    for i in range(s_c):
        for j in range(s_r):
            hsv_sum = hsv_sum + s[i][j]
    hsv_sum = hsv_sum / (s_c * s_r)
    print('mean s =', hsv_sum)

    hsv_sum = 0
    v_c, v_r = v.shape
    for i in range(v_c):
        for j in range(v_r):
            hsv_sum = hsv_sum + v[i][j]
    hsv_sum = hsv_sum / (v_c * v_r)
    print('mean v =', hsv_sum)


# 色彩占比分析
def color_sort(frame, num):
    c = []
    for x in range(frame.shape[0]):
        for y in range(frame.shape[1]):
            c.append(str(frame[x, y][0]) + ',' + str(frame[x, y][1]) + ',' + str(frame[x, y][2]))  # 遍历图片所有bgr值
    temp = Counter(c)
    most = temp.most_common(500)  # 按重复次数排序,抽取排在前500的元素
    count = 1  # 状态值,记录是否是第一个被加入的元素,1代表是
    color = []  # 储存主色彩
    color_num = []  # 储存各主色彩的数量
    for i in most:
        b_i, g_i, r_i = i[0].split(',')  # 待加入色彩
        if count == 1:
            # 第一个被加入的色彩
            color.append(str(b_i) + ',' + str(g_i) + ',' + str(r_i))
            count = 0
            color_num.append(1)
        state = False  # 状态量,若变更为Ture为新颜色,决定加入color内
        for j in color:
            b_o, g_o, r_o = j.split(',')  # 已加入色彩
            # 计算待加入色彩和已加入色彩的区分度,若过为区分度超过阈值则视为要加入的新色彩
            dis = (int(b_o) - int(b_i)) ** 2 + (int(g_o) - int(g_i)) ** 2 + (int(r_o) - int(r_i)) ** 2
            if dis <= threshold:  # 区分度过小,视为列表内已经存在该色彩
                color_num[color.index(j)] += 1
                break
            else:
                state = True  # 修改状态量加入新色彩
            if state and j == color[len(color) - 1]:  # 若所有已有颜色都遍历后state仍为True则加入该色彩
                color.append(str(b_i) + ',' + str(g_i) + ',' + str(r_i))
                color_num.append(1)
                # print(color)
                # print(color_num)
    color_draw(frame, color, color_num, num)  # 绘制色彩占比图


# 绘制色彩占比图
def color_draw(frame, color, color_num, num):
    start = 0
    Height = frame.shape[0]
    Width = frame.shape[1]
    image = cv.resize(frame, (Width, int(Height * 1.125)))  # 创建新画布
    image[0:Height, 0:Width] = frame  # 在新画布上部分填充原图像
    for i in range(len(color)):
        # 遍历所有主色彩,
        print(color[i])
        print(float(color_num[i] / 5), '%')  # 计算百分比,因抽取500个颜色故此处除5便可计算百分比
        b, g, r = color[i].split(',')
        f = int(color_num[i]) * Width / 500  # 计算当前色彩应在画布上的宽度
        image[Height:int(Height * 1.125), start:start + int(f)] = [b, g, r]  # 上色
        start = start + int(f)
    image = cv.cvtColor(image, cv.COLOR_HSV2BGR)
    cv.imshow('result' + str(num), image)
    cv.imwrite('result' + str(num) + '.jpg', image)
    cv.waitKey(0)


def getfiles():
    file_path = '/Users/fbz/Desktop/City_Color/Photos'  # 文件夹路径
    file_names = os.listdir(file_path)
    print(file_names)
    return file_names, file_path


if __name__ == '__main__':
    filenames, path = getfiles()  # 获取文件路径及该路径下的所有照片
    photos_num = 0  # 图片总数量
    for name in filenames:
        if name == '.DS_Store':  # mac电脑在处理文件时需要去除.DS_Store
            continue
        photos_num = photos_num + 1
        file = os.path.join(path, name)
        print(file)
        img = cv.imread(file)
        hsv_img = cv.cvtColor(img, cv.COLOR_BGR2HSV)
        # cv.imshow('frame', frame)
        # cv.waitKey(0)
        calchist_for_rgb(hsv_img, photos_num)  # 第一个参数改为img可以获取BGR直方图
        color_sort(hsv_img, photos_num)  # 第一个参数改为img可以获取BGR直方图

代码仍有很多优化空间,写完之后,和朋友简单讨论了一下,当前的代码对于明度过低和彩度过高的照片效果不够好,大白话就是太暗的图片难以区分出较多的色彩,在区分度计算那里简单的三通道均方根并不能很好的处理黑暗的图片,最好对V通道设定范围,筛选掉低明度的色彩。当然也可以根据直方图自适应筛选,还可以直接提取用修图软件提高整体的亮度。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 伪造图片检测是一种通过计算机视觉技术来判断一张图片是否经过篡改或伪造的方法。Python语言可以通过使用各种开源库和算法来实现图片检测的功能。 首先,图片的检测可以从基本的图像处理开始。Python中的PIL或OpenCV库可以用来读取和处理图像。可以对图片进行基本的预处理,如缩放、裁剪、灰度化等,以减少后续处理的计算量。 接下来,可以使用特征提取算法来提取图片的特征。例如,可以使用图像的色彩分布、纹理、边缘等特征来区分真实图片和伪造图片。常用的特征提取算法有局部二值模式(LBP)、方向梯度直方图(HOG)等。这些算法可以通过Python库,如scikit-image或OpenCV来实现。 在提取了特征之后,可以使用机器学习算法进行分类。通过用真实图片和伪造图片的特征作为输入,训练一个分类器来辨别新的图片是真实还是伪造。常用的分类算法有支持向量机(SVM)、随机森林(Random Forest)等。Python中的scikit-learn库提供了这些算法的实现。 除了机器学习算法,还可以使用深度学习算法进行伪造图片检测。深度学习模型,如卷积神经网络(CNN)可以学习并提取更复杂的特征。可以使用Python中的深度学习框架,如TensorFlow或Keras来实现这些模型。 最后,在实际应用中,可以结合多种方法和算法来进行图片检测。通过综合考虑多个特征和模型的结果,可以提高伪造图片检测的准确性和鲁棒性。 ### 回答2: 伪造图片检测是一种通过计算机视觉技术和图像处理算法来识别、检测和辨别图片是否经过了伪造或篡改的方法。Python是一种功能强大且广泛应用于计算机视觉领域的编程语言,它提供了众多的图像处理库和工具,可以用于开发伪造图片检测的算法和应用。 在进行伪造图片检测时,可以利用Python的图像处理库,如OpenCV和Pillow,对图片进行预处理。首先可以对图片进行降噪处理,通过去除噪声,提高后续处理的准确性。接着可以使用多种算法来分析图像的特征,例如光照变化、纹理、颜色分布等,并与真实图片进行比较来判定是否为伪造图片Python还提供了深度学习库,如TensorFlow和PyTorch,可以利用深度学习算法来训练模型进行伪造图片检测。通过构建卷积神经网络模型,使用大量真实图片和伪造图片训练,可以提高算法的准确性和鲁棒性。 此外,通过使用Python的数字签名、水印和哈希算法等技术,可以对图片进行加密和验证,防止伪造和篡改。 总之,伪造图片检测是一个复杂的问题,但使用Python进行实现是可行且有效的。Python提供了强大的图像处理库和开发环境,可以实现各种算法和技术来检测伪造图片。通过不断改进算法和提高准确性,可以提高伪造图片检测的可靠性和效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱兜圈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值