利用机器学习进行皮肤分割和主色调/颜色提取

sunlinyi 2018-09-12

今天我们将学习使用OpenCV来分割皮肤并使用Sci Kit学习执行K-Means聚类以找到主要的肤色。

假设您了解基本的python并了解OpenCV。我们将涵盖对K-Means和OpenCV的一些方法的高级理解。我们还将讨论不同的色彩空间。

本文的重点是解释代码背后的概念。

什么是OpenCV?

利用机器学习进行皮肤分割和主色调/颜色提取

“OpenCV是一个主要针对实时计算机视觉的编程函数库”

那么什么是计算机视觉?

“计算机视觉涉及从单个图像或一系列图像中自动提取,分析和理解有用信息。它涉及开发理论和算法基础,以实现自动视觉理解。“

计算机视觉是人工智能的一个子领域,它涵盖了从简单的物体识别到生产级机器人的应用。一个示例用例,每个人都可以与Facebook建议在上传照片时标记自己或朋友。

因此,让我们使用高级解释,并为OpenCV做一个简单的定义

“OpenCV是一个计算机视觉库,可帮助我们使用图像处理技术从图像或视频中提取/分析数据”。

什么是Sci-Kit学习?

利用机器学习进行皮肤分割和主色调/颜色提取

“Scikit-learn(以前称为scikits.learn)是一个用于Python编程语言的免费软件机器学习库。它具有各种分类,回归和聚类算法,包括支持向量机,随机森林,梯度增强,k-means和DBSCAN“

机器学习是人工智能的子领域,其重点是为计算机/系统提供自动从数据学习而无需明确编程的算法。它基本上意味着允许计算机在没有“if else”语句的情况下进行预测或假设。

机器学习算法包括

  • 监督学习
  • 无人监督的学习
  • 强化学习

什么是K-Means聚类?

K-Means聚类是一种无监督学习算法。聚类算法的基本原理是它在给定数据集中找到具有相似特征的数据点组。K-Means是一种这样的聚类算法,它将数据分组为“K”组/clusters。

这个过程很简单:

  1. 选择clusters 数量(K)
  2. 随机放置K个数据点(初始质心)
  3. 将数据集中的点分配给最近的质心(这通常是从质心中找到点的欧几里德距离)
  4. 通过获取每个cluster中的数据点的平均值来重新计算新的质心。
  5. 重复3和4直到质心不移动。

利用机器学习进行皮肤分割和主色调/颜色提取

利用机器学习进行皮肤分割和主色调/颜色提取


Python编码

实现的过程:

  • 1. 读取图像 - 这可以使用OpenCV完成
  • 2. 从图像中分割出皮肤 - 这也可以使用OpenCV完成
  • 3. 找到主导色彩 - 这是主要目标!我们将在Scikit-learn python包的帮助下使用K-Mean聚类算法。

所以我们分三个步骤。在您真正理解代码之前需要了解一些事项

1.OpenCV在“BGR Color Space”中读取彩色图像。

这与“RGB色彩空间”相反。

2.使用HSV颜色空间中的阈值处理完成皮肤分割

HSV(Hue, Saturation, Value)是用于表示与人类感知对齐的RGB颜色的模型。Hue表示特定颜色的波长优势,Saturation表示颜色的深浅,Value表示颜色的强度。

阈值处理是通过基于定义的阈值过滤掉像素来创建二值图像的过程。简单来说,取图像的每个像素,如果该像素在“阈值”范围内,如果不使其为黑色,则使其为白色。在我们的上下文中,阈值将是表示“肤色”范围的HSV值。SV的范围可以通过试错得到。

我们将使用cv2.inRange()方法进行阈值处理,并使用cv2.bitwise_and()从二进制图像中获取最终的减影图像。

还有一些其他要点可以了解要使用的库

OpenCV使用Numpy数组作为数据类型。

默认情况下,OpenCV无法处理透明图像。它将透明视为黑色

由于cv2.imshow()在Google Collab中不起作用,我们将使用matplotlib的plypot“imshow”方法来显示图像。

我们将使用PyImageSearch.com的Adrian Rosebrock作者提供的令人敬畏的“ imutils ”库。

Python代码如下:

import numpy as np
import cv2
from sklearn.cluster import KMeans
from collections import Counter
import imutils
import pprint
from matplotlib import pyplot as plt
 
 
def extractSkin(image):
 # Taking a copy of the image
 img = image.copy()
 # Converting from BGR Colours Space to HSV
 img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
 
 # Defining HSV Threadholds
 lower_threshold = np.array([0, 48, 80], dtype=np.uint8)
 upper_threshold = np.array([20, 255, 255], dtype=np.uint8)
 
 # Single Channel mask,denoting presence of colours in the about threshold
 skinMask = cv2.inRange(img, lower_threshold, upper_threshold)
 
 # Cleaning up mask using Gaussian Filter
 skinMask = cv2.GaussianBlur(skinMask, (3, 3), 0)
 
 # Extracting skin from the threshold mask
 skin = cv2.bitwise_and(img, img, mask=skinMask)
 
 # Return the Skin image
 return cv2.cvtColor(skin, cv2.COLOR_HSV2BGR)
 
 
def removeBlack(estimator_labels, estimator_cluster):
 
 # Check for black
 hasBlack = False
 
 # Get the total number of occurance for each color
 occurance_counter = Counter(estimator_labels)
 
 # Quick lambda function to compare to lists
 def compare(x, y): return Counter(x) == Counter(y)
 
 # Loop through the most common occuring color
 for x in occurance_counter.most_common(len(estimator_cluster)):
 
 # Quick List comprehension to convert each of RBG Numbers to int
 color = [int(i) for i in estimator_cluster[x[0]].tolist()]
 
 # Check if the color is [0,0,0] that if it is black
 if compare(color, [0, 0, 0]) == True:
 # delete the occurance
 del occurance_counter[x[0]]
 # remove the cluster
 hasBlack = True
 estimator_cluster = np.delete(estimator_cluster, x[0], 0)
 break
 
 return (occurance_counter, estimator_cluster, hasBlack)
 
 
def getColorInformation(estimator_labels, estimator_cluster, hasThresholding=False):
 
 # Variable to keep count of the occurance of each color predicted
 occurance_counter = None
 
 # Output list variable to return
 colorInformation = []
 
 # Check for Black
 hasBlack = False
 
 # If a mask has be applied, remove th black
 if hasThresholding == True:
 
 (occurance, cluster, black) = removeBlack(
 estimator_labels, estimator_cluster)
 occurance_counter = occurance
 estimator_cluster = cluster
 hasBlack = black
 
 else:
 occurance_counter = Counter(estimator_labels)
 
 # Get the total sum of all the predicted occurances
 totalOccurance = sum(occurance_counter.values())
 
 # Loop through all the predicted colors
 for x in occurance_counter.most_common(len(estimator_cluster)):
 
 index = (int(x[0]))
 
 # Quick fix for index out of bound when there is no threshold
 index = (index-1) if ((hasThresholding & hasBlack)
 & (int(index) != 0)) else index
 
 # Get the color number into a list
 color = estimator_cluster[index].tolist()
 
 # Get the percentage of each color
 color_percentage = (x[1]/totalOccurance)
 
 # make the dictionay of the information
 colorInfo = {"cluster_index": index, "color": color,
 "color_percentage": color_percentage}
 
 # Add the dictionary to the list
 colorInformation.append(colorInfo)
 
 return colorInformation
 
 
def extractDominantColor(image, number_of_colors=5, hasThresholding=False):
 
 # Quick Fix Increase cluster counter to neglect the black(Read Article)
 if hasThresholding == True:
 number_of_colors += 1
 
 # Taking Copy of the image
 img = image.copy()
 
 # Convert Image into RGB Colours Space
 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 
 # Reshape Image
 img = img.reshape((img.shape[0]*img.shape[1]), 3)
 
 # Initiate KMeans Object
 estimator = KMeans(n_clusters=number_of_colors, random_state=0)
 
 # Fit the image
 estimator.fit(img)
 
 # Get Colour Information
 colorInformation = getColorInformation(
 estimator.labels_, estimator.cluster_centers_, hasThresholding)
 return colorInformation
 
 
def plotColorBar(colorInformation):
 # Create a 500x100 black image
 color_bar = np.zeros((100, 500, 3), dtype="uint8")
 
 top_x = 0
 for x in colorInformation:
 bottom_x = top_x + (x["color_percentage"] * color_bar.shape[1])
 
 color = tuple(map(int, (x['color'])))
 
 cv2.rectangle(color_bar, (int(top_x), 0),
 (int(bottom_x), color_bar.shape[0]), color, -1)
 top_x = bottom_x
 return color_bar
 
 
"""## Section Two.4.2 : Putting it All together: Pretty Print
 
The function makes print out the color information in a readable manner
"""
 
 
def prety_print_data(color_info):
 for x in color_info:
 print(pprint.pformat(x))
 print()
 
 
"""
The below lines of code, is the implementation of the above defined function.
"""
 
'''
Skin Image Primary : https://raw.githubusercontent.com/octalpixel/Skin-Extraction-from-Image-and-Finding-Dominant-Color/master/82764696-open-palm-hand-gesture-of-male-hand_image_from_123rf.com.jpg
Skin Image One : https://raw.githubusercontent.com/octalpixel/Skin-Extraction-from-Image-and-Finding-Dominant-Color/master/skin.jpg
Skin Image Two : https://raw.githubusercontent.com/octalpixel/Skin-Extraction-from-Image-and-Finding-Dominant-Color/master/skin_2.jpg
Skin Image Three : https://raw.githubusercontent.com/octalpixel/Skin-Extraction-from-Image-and-Finding-Dominant-Color/master/Human-Hands-Front-Back-Image-From-Wikipedia.jpg
 
'''
 
 
# Get Image from URL. If you want to upload an image file and use that comment the below code and replace with image=cv2.imread("FILE_NAME")
image = imutils.url_to_image(
 "https://raw.githubusercontent.com/octalpixel/Skin-Extraction-from-Image-and-Finding-Dominant-Color/master/82764696-open-palm-hand-gesture-of-male-hand_image_from_123rf.com.jpg")
 
# Resize image to a width of 250
image = imutils.resize(image, width=250)
 
# Show image
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
 
# Apply Skin Mask
skin = extractSkin(image)
 
plt.imshow(cv2.cvtColor(skin, cv2.COLOR_BGR2RGB))
plt.show()
 
# Find the dominant color. Default is 1 , pass the parameter 'number_of_colors=N' where N is the specified number of colors
dominantColors = extractDominantColor(skin, hasThresholding=True)
 
# Show in the dominant color information
print("Color Information")
prety_print_data(dominantColors)
 
# Show in the dominant color as bar
print("Color Bar")
colour_bar = plotColorBar(dominantColors)
plt.axis("off")
plt.imshow(colour_bar)
plt.show()

这将是代码的最终输出,将颜色信息和颜色条如下所示。

利用机器学习进行皮肤分割和主色调/颜色提取

相关推荐