用OpenCV检测图像是卡通还是真人
我正在尝试判断一张图片是卡通画还是一个真实的人。我在网上查了很多资料,尝试了两个提到的算法,但都无法准确判断一张图片是用相机拍的真人,还是卡通/动漫角色。
这是我的脚本:
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