【发布时间】:2013-06-20 07:40:53
【问题描述】:
嗨,我是图像处理和 openCV C/C++ 的新手。我想知道是否可以从第一张图像(面部)中提取肤色。然后应用于第二张图片(body)。
换句话说,用户上传他的面部图像,程序从该图像中提取肤色并将其应用于身体。
谢谢,
爱莎
【问题讨论】:
标签: opencv image-processing skin
嗨,我是图像处理和 openCV C/C++ 的新手。我想知道是否可以从第一张图像(面部)中提取肤色。然后应用于第二张图片(body)。
换句话说,用户上传他的面部图像,程序从该图像中提取肤色并将其应用于身体。
谢谢,
爱莎
【问题讨论】:
标签: opencv image-processing skin
这是一个很难解决的问题,尤其是考虑到颜色会因光照和反射而变化。我以前曾在图像中寻找皮肤,通常 YCbCr 颜色空间的 Cr(色度红色)分量在皮肤上非常突出。您或许可以利用此信息来查找皮肤区域。
这里有几篇尝试使用颜色来定位人体皮肤的论文: 1.Interaction between hands and wearable cameras 2.Markerless inspection of augmented reality objects
【讨论】:
要查找皮肤,您可以使用以下公式之一:
1) 使用归一化 RGB 空间:
for(int i = 0; i < m_image->height; ++i)
{
for(int j = 0; j < m_image->width; ++j)
{
if (m_image->nChannels == 3)
{
int valueR = (reinterpret_cast<uchar*>(m_image->imageData + i * m_image->widthStep))[j * 3 + 2];
int valueG = (reinterpret_cast<uchar*>(m_image->imageData + i * m_image->widthStep))[j * 3 + 1];
int valueB = (reinterpret_cast<uchar*>(m_image->imageData + i * m_image->widthStep))[j * 3];
float normR = static_cast<float>(valueR) / static_cast<float>(valueR + valueG + valueB);
float normG = static_cast<float>(valueG) / static_cast<float>(valueR + valueG + valueB);
float normB = static_cast<float>(valueB) / static_cast<float>(valueR + valueG + valueB);
if ((normB / normG < 1.249) &&
(( normR + normG + normB ) / ( 3 * normR ) > 0.696 ) &&
( 1/3.0 - normB/( normR + normG + normB ) > 0.014 ) &&
(normG/(3* (normR + normG + normB)) < 0.108 ))
{
//pixel is skin
}
}
}
2) 在 RGB 空间中:
for(size_t i = 0; i < m_image->height; ++i)
{
for(size_t j = 0; j < m_image->width; ++j)
{
if (m_image->nChannels == 3)
{
int R = (reinterpret_cast<uchar*>(m_image->imageData + i * m_image->widthStep))[j * 3 + 2];
int G = (reinterpret_cast<uchar*>(m_image->imageData + i * m_image->widthStep))[j * 3 + 1];
int B = (reinterpret_cast<uchar*>(m_image->imageData + i * m_image->widthStep))[j * 3];
if (( R > 95) && ( G > 40 ) && ( B > 20 ) &&
(std::max(R, std::max( G, B) ) - std::min(R, std::min(G, B) ) > 15) &&
(std::abs(R - G) > 15) && (R > G) && (R > B))
{
//skin pixel
}
}
}
3) 在 YCrCb 空间中:
for(size_t i = 0; i < m_image->height; ++i)
{
for(size_t j = 0; j < m_image->width; ++j)
{
if (m_image->nChannels == 3)
{
int Cr = (reinterpret_cast<uchar*>(image->imageData + i * image->widthStep))[j * 3 + 2];
int Cb = (reinterpret_cast<uchar*>(image->imageData + i * image->widthStep))[j * 3 + 1];
int Y = (reinterpret_cast<uchar*>(image->imageData + i * image->widthStep))[j * 3];
if (( Y > 80 ) && ( Cb > 85 ) && ( Cb < 135 ) &&
(Cr > 135) && (Cr < 180))
{
//skin pixel
}
}
}
}
【讨论】:
int main() { Mat ycrcb; Mat ycrcb1; Mat inputImage = imread("Skin image",1); Mat Image = imread("body image",1); cvtColor(inputImage,ycrcb,CV_BGR2YCrCb); cvtColor(Image,ycrcb1,CV_BGR2YCrCb); vector<Mat> channels; split(ycrcb,channels); vector<Mat> channels1; split(ycrcb1,channels1); channels1[0] = channels[0]; channels1[1] = channels[1]; channels1[2] = channels[2]; Mat result; merge(channels1,ycrcb1); cvtColor(ycrcb1,result,CV_YCrCb2BGR); imshow("new body image",result); return 0; }