用OpenCV检测图像是卡通还是真人

4 投票
2 回答
2805 浏览
提问于 2025-04-17 21:23

我正在尝试判断一张图片是卡通画还是一个真实的人。我在网上查了很多资料,尝试了两个提到的算法,但都无法准确判断一张图片是用相机拍的真人,还是卡通/动漫角色。

这是我的脚本:

detectCartoon1使用拉普拉斯方法来判断一张图片是不是人。我想相机拍的照片质量会比较低,所以这个方法应该有效。但结果不如人意——我得到了很多错误的判断。

detectCartoon2使用了另一个人在Stack Overflow上提到的方法。这个方法认为,给卡通图像应用滤镜后,变化不会太大;但如果是用低质量相机或网络摄像头拍的照片,变化会很明显。结果还是出现了很多错误的判断。

我在网上搜索其他方法,或者试图想出自己的方法,但就是想不出来。对此话题的任何帮助我都非常感激。

谢谢!

import cv2
import numpy

def detectCartoon1(imagePath):
    img_before = cv2.imread(imagePath)
    img_after = 0    

    gray = cv2.GaussianBlur(img_before, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
    gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
    img_after = cv2.Laplacian(gray, cv2.CV_64F)
    img_after = cv2.convertScaleAbs(img_after)

    return numpy.mean(img_after)    

def detectCartoon2(imagePath):
    img_before = cv2.imread(imagePath)
    img_after = 0

    for i in range(1, 31, 2):
        img_after = cv2.bilateralFilter(img_before, i, i*2, i/2)

    img_after = cv2.cvtColor(img_after, cv2.COLOR_HSV2BGR_FULL)
    img_before = cv2.cvtColor(img_before, cv2.COLOR_HSV2BGR_FULL)

    return numpy.mean(img_before - img_after)

from os import listdir

for img in listdir('Save'):
    img = 'Save\\' + img
    dc1 = detectCartoon1(img)
    dc2 = detectCartoon2(img)
    print('Img: ' + img + ' detectCartoon1: ' + str(dc1) + ' detectCartoon2: ' + str(dc2))

2 个回答

0

总结一下:八年后的回答是 - 使用 机器学习

我自己试过一些方法,发现稍微调整一下,opencv在检测卡通图像方面还算“可以”。通过模糊处理和比较直方图,我能达到大约70%的准确率。

from pathlib import Path
from typing import Union

import cv2


def is_cartoon(image: Union[str, Path], threshold: float = 0.98) -> bool:
    # real people images:  79.5%     all: 2149 | cartoon: 440 | real: 1709
    # cartoon images:      59.4%     all: 481 | cartoon: 286 | real: 195

    # read and resize image
    img = cv2.imread(str(image))
    img = cv2.resize(img, (1024, 1024))

    # blur the image to "even out" the colors
    color_blurred = cv2.bilateralFilter(img, 6, 250, 250)

    # compare the colors from the original image to blurred one.
    diffs = []
    for k, color in enumerate(('b', 'r', 'g')):
        # print(f"Comparing histogram for color {color}")
        real_histogram = cv2.calcHist(img, [k], None, [256], [0, 256])
        color_histogram = cv2.calcHist(color_blurred, [k], None, [256], [0, 256])
        diffs.append(cv2.compareHist(real_histogram, color_histogram, cv2.HISTCMP_CORREL))

    return sum(diffs) / 3 > threshold

我还尝试了一种“更简单”的方法,但结果发现这种方法需要更多的计算资源,就是统计图像中的颜色。然后看看如果只用前512种颜色,能重现出多少图像。总体来说,这种方法的准确率大约是75%。

def is_cartoon_color_count(image: Union[str, Path], threshold: float = 0.3) -> bool:
    #real:     71%
    #cartoon:  80%
    # Much slower due to CPU overhead of color counting. Recommend multiprocess pool if using

    img = cv2.imread(str(image))
    img = cv2.resize(img, (1024, 1024))
    # img = cv2.bilateralFilter(img, 6, 250, 250)

    # Find count of each color
    color_count = {}
    for row in img:
        for item in row:
            value = tuple(item)
            if value not in color_count:
                color_count[value] = 1
            else:
                color_count[value] += 1

    # Identify the percent of the image that uses the top 512 colors
    most_common_colors = sum([x[1] for x in sorted(color_count.items(), key=lambda pair: pair[1], reverse=True)[:512]])
    return (most_common_colors / (1024 * 1024)) > threshold

不过,这个问题也比较老了。所以我觉得用更现代的方法,比如机器学习,会更好。

我基于Keras和TensorFlow构建了自己的训练模型,使用同样的样本集,我的准确率达到了95%(卡通检测92%,真实图像超过99%)。

1

这里有一篇关于你问题的好文章:http://www.uv.es/~tzveta/invwork.pdf

撰写回答