python之图像背景识别

简介: 需求:在某个手机端项目中,有多个页面图片,但每个图片都做了相应的修改,由于这种图片非常多,高达上万张,每周有新的内容出现且需要回归。在某些特定的节点,不允许相邻两张出现一模一样的图片,如果人去判定,非常非常耗时,于是需要自动化筛选,人工复核。

python之图像背景识别

本着结合实际工作,实际落地并已应用的态度去码文。

python之对比两张图像的相似度

需求:在某个手机端项目中,有多个页面图片,但每个图片都做了相应的修改,由于这种图片非常多,高达上万张,每周有新的内容出现且需要回归。

在某些特定的节点,不允许相邻两张出现一模一样的图片,如果人去判定,非常非常耗时,于是需要自动化筛选,人工复核。

得,又接了一个非专业技能内的活,咋办,硬着头皮上?

那肯定不行,因为我不会;

但专业职场人怎么能说自己不会,不能!你得说,我可以学!

于是乎,我开始查找资料开始学习,找了一大圈,发现,AirTest里面就有这么一个API能够满足我的需求。拿来吧你,嘿嘿~

大致捋一下,所有页面图片通过自动化进行截图,在某些特定节点对图片命名中加入下划线作为区分,单独拿出特定节点的图片进行两两比较。

image-20221206144400568.png

代码如下:[增加了日志追加写入并换行记录]

makeFolderResult方法为创建日志文件夹。

writeLog方法为将对比失败的图片名称写入日志中。[该日志将会直接写入目标图片路径根目录]

imageCompare方法为实际对比逻辑,阈值范围为0~1,越接近1表示图片相似度越高。

from airtest.aircv.cal_confidence import *

def makeFolderResult(imgPath, logName):
    logFloder = os.path.join(imgPath, f'图片对比结果')
    os.mkdir(logFloder)
    logPath = os.path.join(imgPath, f'图片对比结果/{logName}')
    return logPath

def wirteLog(msg, logPath):
    with open(logPath, "a+", encoding='utf-8') as f:
        f.write(msg)
        f.write("\n")

def imageCompare(imagePath, logPath,threshold:int):
    '''
    :param imagePath: 图片存放的路径
    :param logPath: 日志存放的路径
    :param threshold: 阈值,指定int类型
    :return: 
    '''
    needCompareImgDict = {}
    for root, dirs, files in os.walk(imagePath):
        for file in files:
            if "_" in file:
                key = str(file).split("_")[0]
                if key not in needCompareImgDict.keys():
                    needCompareImgDict[key] = [os.path.join(root, file)]
                else:
                    tempList = needCompareImgDict[key]
                    tempList.append(os.path.join(root, file))
                    needCompareImgDict[key] = tempList
    #### 遍历字典,将同个ID下的图片进行对比
    for imgs in needCompareImgDict.values():
        for i in range(len(imgs) - 1):
            img_1_path = imgs[i]
            img_2_path = imgs[i + 1]
            img_1_Name = img_1_path.split("\\")[-1]
            img_2_Name = img_2_path.split("\\")[-1]
            img1 = cv2.resize(cv2.imread(img_1_path), (370, 800)) # 图片尺寸根据实际图片写入
            img2 = cv2.resize(cv2.imread(img_2_path), (370, 800))
            confidence = cal_ccoeff_confidence(img1, img2)
            if confidence > threshold:
                writeMsg = f"【对比失败】,疑似 {img_1_Name}  与  {img_2_Name} 两张图片一致,相似度为:{round(confidence * 100, 2)}%"
                wirteLog(writeMsg, logPath)
                print(writeMsg)
            else:
                pass

if __name__ == '__main__':
    imagePath = "填入你图片存放的路径"
    logName = str(imagePath.split("\\")[-1]) + ".txt"
    logPath = makeFolderResult(imagePath, logName)
    imageCompare(imagePath, logPath)

cal_ccoeff_confidence这个API是核心,源码如下:

import cv2
import numpy as np
from .utils import img_mat_rgb_2_gray


def cal_ccoeff_confidence(im_source, im_search):
    """求取两张图片的可信度,使用TM_CCOEFF_NORMED方法."""
    # 扩展置信度计算区域
    im_source = cv2.copyMakeBorder(im_source, 10,10,10,10,cv2.BORDER_REPLICATE)
    # 加入取值范围干扰,防止算法过于放大微小差异
    im_source[0,0] = 0
    im_source[0,1] = 255

    im_source, im_search = img_mat_rgb_2_gray(im_source), img_mat_rgb_2_gray(im_search)
    res = cv2.matchTemplate(im_source, im_search, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    return max_val

有兴趣的小伙伴可以自己研究,没兴趣的如果遇到了,拿来就直接用。

python之筛选图像中是否存在黑白背景

紧接上篇文章的需求,需要进行功能增加

某些图片存在背景丢失问题,出现黑白背景现象,这种需要排查,同样交给了自动化处理。

这次不比上次了,我搜罗了一堆资料,全是什么人工智能领域的图像识别,AI识别之类的,没有能够符合我需求的,看来CV大法这次是失策了。

那如何找到突破口?毕竟这可是工作,还是我主动请缨,我原先思路也很简单,上篇文章中提到使用AirTest库中的cal_ccoeff_confidence这个方法可以实现图片对比,那么我自己做一张纯黑和纯白的图片,拿目标图片和这两张图片进行对比,相似度越高,不就代表目标图片可能存在背景丢失问题吗?

理论可行,实践失败。

我曾经学了点UI,稍微知道一点,图像一个像素点由三个数值组成,如纯白色可以用(255,255,255)来表示,纯黑色可以用(0,0,0)来表示。RGB与十六进制颜色码转换 - 在线工具 (toolhelper.cn)

image-20221206142719667.png
image-20221206142705523.png

在搜集的资料中,图像对比处理都是采用的黑白化(灰度图)图片进行取值,我用比较通俗的话来讲:

提取一张图片中所有像素点的值,将这个值和纯黑或纯白像素点的值进行差值计算,

另外一张图片也是如此,

最后将这两张图片的所有点进行挨个计算,最后算出均值,从而判断两张图片是否相似。

专业领域称之为均值哈希算法

有兴趣的小伙伴可以去研究,均值哈希算法、差值哈希算法、感知哈希算法、灰度直方图算法

均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1

这些东西对我来说,晦涩难懂,而且我看它们显得我就是个文盲,不过还是得理性分析一波,为什么实践失败了呢?

第一,我是要找黑白背景,而他们都是由哈希值来求取,黑白在两个极值点,我无法准确判断是否为黑或者白;

第二,我使用cal_ccoeff_confidence方法求出来的值直接是负数,转手使用cal_rgb_confidence彩图计算相似度也是负数,而且比前者更离谱,要么我不会用,要么我这需求人家根本没考虑过。

第三,出发点不一样,我需要的是极值点数据,查找的方法都是求整体对比。

如何解决?

前面有提到,每一个像素值都是由三个数字组成的元组,那么就有256*256*256种颜色,在以前的公司还考虑过8位16位24位32位色,但现在都是由我截的图,都是统一的,所以不用去考虑。

而在正常的UI设计规范中,是不会允许出现纯黑纯白颜色出现的,也就是(255,255,255)(0,0,0)这两种。

想清楚这个,问题就相对来说走上了正轨,不会被所查找的资料给带跑偏了,我们开始一步步推导:

1、我们需要找丢失背景的图片,意味着这张图片的背景被纯黑色或者纯白色占据了大部分。

2、既然是纯黑或纯白占据大部分,那么我们可以提取一张图片上所有的像素点的值,并按数量从大到小取值。

3、取值只取前三,如果前三中,排名第一多的是纯黑或者纯白,那么我们判断该图片为背景缺失。

4、如果为(255,255,255)则记录该图片背景丢失,背景为白色

5、如果为(0,0,0)则记录该图片背景丢失,背景为黑色

在实际操作下来发现,白色并不一定完全是纯白,还有个范围差,于是我取值为三项都是大于251,判断为白色,三项都是小于10,且每项相等,为黑色。(通过多次实验数据分析得出的谨代表个人观点的结论)。

如果想要判断背景是红色、绿色之类的,可以自己去查找颜色范围,将取值范围和相关算法匹配写到代码里面就行了。

以上这些都是实际实践并有产出的,本着宁愿多判定两张,绝不漏掉一张的本质,白色的99%都能识别准确,黑色的识别准确度会低一点,黑色会多判定一些(有部分转场截屏是黑的也算进去了),最终也需要人工复核,但一般5000张图片,关于背景缺失问题,人工复核只需要5分钟不到。

image-20221206144150704.png

以下为脱敏后代码,整体逻辑都在文章中了,不懂的地方自行百度吧,我写累了,懒子一个不想多写了:

def makeFolderResult(imgPath, logName):
    logFloder = os.path.join(imgPath, f'背景缺失对比结果')
    os.mkdir(logFloder)
    logPath = os.path.join(imgPath, f'背景缺失对比结果/{logName}')
    return logPath

def wirteLog(msg, logPath):
    with open(logPath, "a+", encoding='utf-8') as f:
        f.write(msg)
        f.write("\n")

def get_dominant_colors(imagePath, logPath):
    '''
    :param imagePath: 图片存放的路径
    :param logPath: 日志存放的路径
    :return:
    '''
    for root, dirs, files in os.walk(imagePath):
        for file in files:
            if ".jpg" in file:
                imgFile = os.path.join(root, file)
                image = Image.open(imgFile)
                # 缩小图片,减少运算压力
                small_image = image.resize((80, 80))
                result = small_image.convert("P", palette=Palette.ADAPTIVE, colors=10)
                # 10个主要颜色的图像
                # 找到主要的颜色
                palette = result.getpalette()
                color_counts = sorted(result.getcolors(), reverse=True)
                colors = list()
                for i in range(3):
                    try:
                        palette_index = color_counts[i][1]
                        dominant_color = palette[palette_index * 3: palette_index * 3 + 3]
                        colors.append(tuple(dominant_color))
                    except:
                        break
                ### 判定数量排名第一的颜色是否满足黑或白
                firstColor = colors[0]
                ### 计算平均值
                try:
                    firstColorAvg = numpy.average(firstColor)
                    if firstColorAvg > 251:
                        if firstColor[0] > 251 and firstColor[1] > 251 and firstColor[2] > 251:
                            writeMsg = f"【疑似】{file}背景为 【白色】"
                            wirteLog(writeMsg, logPath)
                            print(writeMsg, firstColor)
                    elif 0 =< firstColorAvg < 10:
                        if firstColor[0] == firstColor[1] == firstColor[2]:
                            writeMsg = f"【疑似】{file}背景为 【黑色】"
                            wirteLog(writeMsg, logPath)
                            print(writeMsg, colors)
                except:
                    traceback.print_exc()
if __name__ == '__main__':
    imagePath = ""
    logName = str(imagePath.split("\\")[-1]) + ".txt"
    logPath = makeFolderResult(imagePath, logName)
    get_dominant_colors(imagePath, logPath)

最终会将结果写入到目标图片文件夹下的log中。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
4天前
|
机器学习/深度学习 Python
【Python实战】——神经网络识别手写数字(三)
【Python实战】——神经网络识别手写数字
|
4天前
|
机器学习/深度学习 数据可视化 Python
【Python实战】——神经网络识别手写数字(二)
【Python实战】——神经网络识别手写数字(三)
|
4天前
|
Serverless Python
Python----图像的手绘效果
Python----图像的手绘效果
7 1
|
4天前
|
数据采集 文字识别 测试技术
神器!使用Python 轻松识别验证码
本文介绍了使用Python进行验证码识别,主要包括安装Tesseract OCR和相关Python库,如`pytesseract`和`opencv-python`。通过Pillow加载验证码图片,使用`pytesseract`进行简单数字验证码识别。对于数字字母混合的验证码,先进行二值化和降噪处理,然后使用`cv2.findContours`分割字符并分别识别。这种方法适用于自动化测试和爬虫中的验证码处理。
28 2
|
4天前
|
机器学习/深度学习 数据可视化 Python
【Python实战】——神经网络识别手写数字(一)
【Python实战】——神经网络识别手写数字
|
4天前
|
监控 算法 计算机视觉
探索图像边缘:使用Python进行轮廓检测
探索图像边缘:使用Python进行轮廓检测
30 3
|
4天前
|
机器学习/深度学习 计算机视觉 Python
使用Python改变图像颜色的实用指南
使用Python改变图像颜色的实用指南
11 1
|
4天前
|
机器学习/深度学习 计算机视觉 Python
【Python 机器学习专栏】图像数据的特征提取与预处理
【4月更文挑战第30天】本文探讨了图像数据的特征提取与预处理在机器学习中的重要性。图像数据具有大容量、信息丰富和冗余性高的特点。特征提取涉及颜色、纹理和形状特征;预处理包括图像增强、去噪和分割。Python的OpenCV和Scikit-image库在处理这些任务时非常有用。常见的特征提取方法有统计、变换和基于模型的方法,而预处理应注意保持图像真实性、适应性调整及验证评估。有效的特征提取和预处理能提升模型性能,Python工具使其更高效。
|
4天前
|
机器学习/深度学习 PyTorch 算法框架/工具
Python用GAN生成对抗性神经网络判别模型拟合多维数组、分类识别手写数字图像可视化
Python用GAN生成对抗性神经网络判别模型拟合多维数组、分类识别手写数字图像可视化
|
4天前
|
机器学习/深度学习 人工智能 计算机视觉
使用Python实现简单的图像识别应用
本文介绍了如何使用Python编写一个简单的图像识别应用程序。通过结合Python的图像处理库和机器学习库,我们可以轻松地构建一个能够识别特定物体或图案的程序。本文将从安装必要的库开始,然后逐步介绍如何编写代码来实现图像的加载、处理和识别。