2016-05-09 21:25

基于色度分量的简单图像识别

我们一般接触到的图像识别技术多是各大搜索引擎的图片搜索,在这方面做的最好的非Google莫属。我曾经几次想找到手上的图片源图,分别用了Google、Bing、360、baidu等,Google对于有版权的图片,不只是推荐相似图片,第一条结果就是摄影师的官网,第二条结果是其Faceboook地址。而度娘对图片的判断是星空倒是没错,但推荐的图片简直就是侮辱人类的智商。(星空图见底部)

下面这个Demo仅是测试用例,源于项目中用的直播和图片鉴黄辅助监控。从最简单的方法入手,就是用 YCbCr 色彩空间来提取Cb和Cr色度分量,判断其肤色范围比重,方法简单误差自然也就大,作为人工辅助工具使用还是可以的。再优化一下,可以先定位身体位置,然后再进行色量判断。再复杂的方案可以做特征“指纹”分析,或对已有类型标记的图片库做AI学习,根据学习的结果数据库对图片进行鉴定分析,这只能交给专业领域的人去做了。

这里使用YCbCr方法做一个简单测试:

from PIL import Image
import os, glob

def get_skin_ratio(im):
    im = im.crop((int(im.size[0]*0.2), int(im.size[1]*0.2), im.size[0]-int(im.size[0]*0.2), im.size[1]-int(im.size[1]*0.2)))
    skin = sum([count for count, rgb in im.getcolors(im.size[0]*im.size[1]) if rgb[0]>60 and rgb[1]<(rgb[0]*0.85) and rgb[2]<(rgb[0]*0.7) and rgb[1]>(rgb[0]*0.4) and rgb[2]>(rgb[0]*0.2)])
    return float(skin)/float(im.size[0]*im.size[1])
def ck_img_ratio(image_file):
    skin_percent = get_skin_ratio(Image.open(image_file)) * 100
    return '{0:.0f}'.format(skin_percent)

def image_ifo(image):
    try:
        img = Image.open(image)
    except Exception as e:
        print("Can not open the image!")
    return img
def preprocessed_image(image):
    img = image_ifo(image)
    if not img.mode == 'YCbCr':
        img = img.convert('YCbCr')
    return img
    
def detector(image):
    img = preprocessed_image(image)
    ycbcr_data = img.getdata()
    W,H = img.size
    count = 0
    for i,ycbcr in enumerate(ycbcr_data):
        y,cb,cr = ycbcr
        if 86 <= cb <= 117 and 140 <= cr <= 168:
            count += 1
    return format(count/(W*H), '.0%')

def each_dir_file():
    for image_dir in ('d1','d2','d3'):
        print("-" * 30, "Dir : ", image_dir)
        fun1 = fun2 = ''
        for image_file in glob.glob(os.path.join(image_dir,"*.jpg")):
            fun1 += '{0:3}-'.format(detector(image_file))
            fun2 += '{0:3}-'.format(ck_img_ratio(image_file))
        print('M1:', fun1)
        print('M2:', fun2)
        
if __name__ == '__main__':
    each_dir_file()

结果分析:Demo中使用了两种计算方法(M1、M2)。在包含风景和人物的目录d1中,结果超出30%的图片有4张,其中91%那张其实是沙地,因为和肤色接近,所以值也比较较高;比基尼居多的d2目录,命中结果还是比较高的;但d3目录只所以结果值都比较低,主要是受肤色影响。

------------------------------ Dir :  d1
M1: 0% -8% -17%-1% -5% -56%-11%-15%-2% -2% -7% -1% -91%-18%-4% -39%-11%-4% -0% -12%-28%-37%-3% -10%-
M2: 0  -18 -20 -1  -12 -34 -31 -27 -5  -5  -17 -2  -84 -36 -8  -25 -10 -11 -0  -15 -12 -28 -6  -13 -
------------------------------ Dir :  d2
M1: 74%-42%-34%-40%-77%-45%-31%-42%-67%-58%-44%-40%-48%-69%-35%-21%-58%-28%-30%-57%-6% -9% -
M2: 78 -58 -63 -31 -95 -63 -57 -58 -63 -61 -66 -55 -49 -71 -54 -43 -48 -59 -43 -65 -4  -10 -
------------------------------ Dir :  d3
M1: 7% -25%-20%-0% -56%-
M2: 17 -32 -25 -0  -36 -

上述Demo是对全图的分析,在此基础上我们可以先识别身体特征,比如图片中是否有面部,上半身,下半身。如果监测到这些部位,再对此部位进行局部色量分析,如果有面部特征,可以提取面部的色量值,然后根据此值来分析身体色量值,做到适应肤色判断。对身体的分析OpenCV默认提供的特征库效果一般般,成功率很低,这里也就没在继续测试。

另外也可以使用一些第三方的分析方案,如:阿里、腾讯云、Clarifai(擅长图片视频深度学习,很NB的样子,目前提供多种API服务)...