Android Studio+OpenCV:手部检测项目中从YCrCb图像获取皮肤HSV值
手部检测项目:Android Studio + OpenCV 提取皮肤区域HSV值方案
嘿,我来帮你一步步搞定这个需求——从YCrCb色彩空间定位皮肤,再提取对应的HSV值,还要计算皮肤区域的HSV统计信息,对吧?下面是具体的实现步骤和代码示例,都是Android平台上用OpenCV的实操内容:
1. 先确认OpenCV在Android Studio的配置(快速回顾)
如果还没配置,其实很简单:
- 下载OpenCV Android SDK,解压后把
sdk/java目录导入到你的Android项目作为模块 - 在app模块的
build.gradle里添加对这个OpenCV模块的依赖 - 在你的Activity里初始化OpenCV(建议在onCreate前完成):
static { if (!OpenCVLoader.initDebug()) { // 这里可以加个Toast或者日志提示初始化失败 } }
2. 核心流程:从YCrCb提取皮肤掩码 → 转换到HSV → 计算HSV值
步骤拆解与代码实现
下面的代码可以放在相机帧处理回调(比如CameraBridgeViewBase.CvCameraViewListener2的onCameraFrame方法)里,或者处理本地图片的函数中:
import org.opencv.core.*; import org.opencv.imgproc.Imgproc; import java.util.Collections; public Mat processHandFrame(Mat inputFrame) { // 1. 把输入帧(默认BGR格式)转成YCrCb色彩空间 Mat ycrcbMat = new Mat(); Imgproc.cvtColor(inputFrame, ycrcbMat, Imgproc.COLOR_BGR2YCrCb); // 2. 定义YCrCb的皮肤阈值——这个范围是行业内常用的皮肤检测区间,你可以根据测试场景微调 Scalar lowerSkinThreshold = new Scalar(0, 133, 77); Scalar upperSkinThreshold = new Scalar(255, 173, 127); Mat skinMask = new Mat(); // 生成皮肤掩码:符合阈值的像素为255(白色),其余为0(黑色) Core.inRange(ycrcbMat, lowerSkinThreshold, upperSkinThreshold, skinMask); // 可选优化:对掩码做形态学操作,去除小噪声点,让皮肤区域更平滑 Mat morphKernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5, 5)); Imgproc.dilate(skinMask, skinMask, morphKernel); Imgproc.erode(skinMask, skinMask, morphKernel); // 3. 把原BGR帧转成HSV色彩空间 Mat hsvMat = new Mat(); Imgproc.cvtColor(inputFrame, hsvMat, Imgproc.COLOR_BGR2HSV); // 4. 用皮肤掩码提取仅包含皮肤区域的HSV图像 Mat skinHSVRegion = new Mat(); hsvMat.copyTo(skinHSVRegion, skinMask); // 5. 计算皮肤区域的HSV统计值 // 方式1:计算HSV三个通道的均值(最常用的代表值) Scalar meanHSV = Core.mean(skinHSVRegion, skinMask); Log.d("SkinHSV", "平均H值: " + meanHSV.val[0] + ", 平均S值: " + meanHSV.val[1] + ", 平均V值: " + meanHSV.val[2]); // 方式2:计算HSV各通道的最小/最大值(获取范围) Core.MinMaxLocResult hRange = Core.minMaxLoc(skinHSVRegion.submat(0, skinHSVRegion.rows(), 0, 1)); Core.MinMaxLocResult sRange = Core.minMaxLoc(skinHSVRegion.submat(0, skinHSVRegion.rows(), 1, 2)); Core.MinMaxLocResult vRange = Core.minMaxLoc(skinHSVRegion.submat(0, skinHSVRegion.rows(), 2, 3)); Log.d("SkinHSVRanges", "H范围: " + hRange.minVal + " ~ " + hRange.maxVal); Log.d("SkinHSVRanges", "S范围: " + sRange.minVal + " ~ " + sRange.maxVal); Log.d("SkinHSVRanges", "V范围: " + vRange.minVal + " ~ " + vRange.maxVal); // 方式3:生成HSV直方图(查看颜色分布) MatOfInt channels = new MatOfInt(0, 1, 2); // 对应H、S、V三个通道 MatOfInt histSize = new MatOfInt(180, 256, 256); // H的范围是0-179,S/V是0-255 MatOfFloat ranges = new MatOfFloat(0, 180, 0, 256, 0, 256); Mat hsvHist = new Mat(); Imgproc.calcHist(Collections.singletonList(skinHSVRegion), channels, skinMask, hsvHist, histSize, ranges); // 这里可以把直方图数据导出做进一步分析,比如找峰值颜色 // 别忘了释放Mat资源,避免内存泄漏 ycrcbMat.release(); skinMask.release(); hsvMat.release(); skinHSVRegion.release(); channels.release(); histSize.release(); ranges.release(); hsvHist.release(); return inputFrame; // 返回原帧或者处理后的掩码帧都可以,看你的需求 }
关键细节说明
- YCrCb皮肤阈值选择:Cr通道对应红色分量,Cb对应蓝色分量,皮肤的Cr值通常在133-173之间,Cb在77-127之间,这个范围对黄种人、白种人都有不错的检测效果,如果你是针对特定肤色人群,可以用样本图片调整阈值。
- 色彩空间转换注意:OpenCV在Android中获取的相机帧是BGR格式,所以转换时要用
COLOR_BGR2YCrCb和COLOR_BGR2HSV,别误用RGB相关的转换常量。 - 掩码的作用:
copyTo方法传入掩码后,只会把掩码中白色区域(255)对应的像素复制到目标Mat,这样就只保留了皮肤区域的HSV数据,避免背景干扰。
3. 调试小技巧
- 可以把
skinMask转换成BGR格式显示在界面上,看看皮肤检测的准确率,调整阈值或者形态学操作的参数 - 打印出来的均值和范围可以用来后续的皮肤跟踪或者手势识别,比如设置HSV的皮肤阈值做二次验证
内容的提问来源于stack exchange,提问作者sobia qaiser
相关产品推荐
相关产品推荐

