检测皮肤和捕捉图像

4

更新1

我知道inRange函数的作用,但我不想应用掩模并显示肤色的新图像。我想知道的是图像是否包含肤色并覆盖更大的区域。

我想要做什么

我想在检测到手指在一个边界内时捕获一张照片。它的尺寸已知。

困扰的地方

  1. 在本地代码中操作图像数据。
  2. 在实时相机中检测皮肤,所以每当焦点集中在特定区域且检测到皮肤时,应该拍摄快照。

我已经做了什么

我正在使用JNI层来执行操作。我能够使用这个教程从图像数据中获取Mat,但不知道如何操作poutPixels。格式为NV21,我不确定如何对其进行操作。

我需要裁剪图像,然后检测图像中是否存在肤色。我已经成功将图像裁剪到所需的尺寸,但不知道如何继续检测肤色。我希望这个方法返回truefalse

以下是代码:

jbyte * pNV21FrameData = env->GetByteArrayElements(NV21FrameData, 0);
jint * poutPixels = env->GetIntArrayElements(outPixels, 0);

Mat mNV(height, width, CV_8UC3, (unsigned char*)pNV21FrameData);
Mat finalImage(height, width, CV_8UC3, (unsigned char*) poutPixels);

jfloat wScale = (float) width/screenWidth;
jfloat hScale = (float) height/screenHeight;

float temp = rectX * wScale;
int x = (int) temp;
temp = rectY * hScale;
int y = (int) temp;

int cW = (int) (width * wScale);
int cH =  (int) (height * hScale);

cH = cH/2;


Rect regionToCrop(x, y, cW, cH);
mNV = mNV(regionToCrop);
finalImage = finalImage(regionToCrop);

//detect skin and return true or false

我已经了解了inRange函数,但我不知道如何检查是否有皮肤。

问题

  1. 我在继续进行的正确路径上吗?
  2. 我得到的图像格式是NV21。它是8UC1还是可以是8UC3
  3. 从这里开始如何进行皮肤检测?

任何帮助都将不胜感激。

1个回答

1
我已经通过提取肤色范围并将所有像素设置为零来解决了我的问题。以下是步骤。
  1. 将图像转换为HSV

首先将图像转换为HSV

Mat mHsv = new Mat(rows, cols, CvType.CV_8UC3);
Imgproc.cvtColor(mRgba, mHsv, Imgproc.COLOR_RGB2HSV);
  1. 获取肤色范围

肤色范围可能会有所不同,但这个对我来说很有效。

Mat output = new Mat();
Core.inRange(mHsv, new Scalar(0, 0.18*255, 0), new Scalar(25, 0.68*255, 255), output);
  1. 提取这个皮肤范围的通道

现在提取这个通道,同时将皮肤像素设为

Mat mExtracted = new Mat();
Core.extractChannel(output, mExtracted, 0);

现在你有一个名为mExtracted的矩阵,其中肤色像素为0,其他为255(或肤色,我不确定)。

  1. 获取零的数量

由于0现在实际上是肤色区域,您可以定义适合您需要的阈值。根据我的需求,我希望肤色覆盖超过一半的区域,因此我相应地进行了逻辑设置。

int n = Core.countNonZero(mExtracted);
int check = (mExtracted.rows() * mExtracted.cols())/2;

if(n >= check && isFocused) {
    //Take picture
}

在投下负评之后评论一下是非常好的举动,这样其他人也可以从您的智慧中学到东西。 - Waqas Ahmed Ansari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接