株洲seo网站优化,新加坡网站后缀,杭州网站推广服务,网站域名重要吗最近在小红书上看到很多更换证件照背景色的需求#xff0c;联想到以前自己也更换过证件照背景色而且还是付费的#xff0c;碰巧最近在看一本书《JavaOpenCV高效入门》#xff0c;于是查找资料#xff0c;找到了通过技术解决这个需求的办法。 先看效果图#xff08;图片来自…最近在小红书上看到很多更换证件照背景色的需求联想到以前自己也更换过证件照背景色而且还是付费的碰巧最近在看一本书《JavaOpenCV高效入门》于是查找资料找到了通过技术解决这个需求的办法。 先看效果图图片来自网络如有侵权请联系我删除
下面直接上代码只需要一个函数就可以了
/*** 算法实现步骤* 1、加载原图像* 2、制作kmeans输入参数所需要的数据kmeans的输入数据类型是CV_32F所以不能直接使用原始图像的数据因为原始图像的数据类型为CV_8UC1* 3、使用kmeans算法实现图像分类并得到分类标签* 4、创建遮罩通过分类标签将背景部分的颜色标记位0将前景人物像素值标记位255* 5、先对mask执行形态学操作去除干扰的白点在使用高斯模糊平滑前景和背景之前的过度* 6、创建一个3通道的目标输出结果Mat然后将目标背景填充到背景区域将前景部分填充到前景区域。* 7、输出图像* ps算法的核心步骤其实就是找到mask当mask找到之后就可以使用分类标签将背景和前景替换成为自己想要的像素。* 参考https://www.cnblogs.com/tony-yang-flutter/p/16153446.html* param photoPath 本地图片路径* param rgbEnd 目标背景色* return*/Overridepublic Mat changePhotoBackgroundColor(String photoPath, double[] rgbBeg, double[] rgbEnd) {Mat src Imgcodecs.imread(photoPath);//制作kmeans需要的数据int width src.cols();int height src.rows();int dims src.channels();int sampleCount width*height;//总共的像素点Mat points new Mat(sampleCount, dims, CvType.CV_32F,new Scalar(10));int index 0;for(int row 0;rowheight;row){for(int col 0;colwidth;col){index row * width col;double[] bgr src.get(row, col);points.put(index,0, bgr[0]);points.put(index,1, bgr[1]);points.put(index,2, bgr[2]);}}int numCluster 4;//多少个分类Mat labels new Mat();//分类标签Mat centers new Mat();//中心点TermCriteria criteria new TermCriteria(TermCriteria.EPS TermCriteria.COUNT, 10, 0.1);kmeans(points,numCluster,labels,criteria,3,KMEANS_PP_CENTERS,centers);//创建遮罩Mat mask Mat.zeros(src.size(),CvType.CV_8UC1);//找到背景像素的像素点位置index src.rows() * 2 2;//找到像素点位置在labels中所对应的标签找到这个标签以后就可以根据这个标签来判断前景和背景double[] cIndex labels.get(index,0);for(int row0;rowheight;row){for(int col0;colwidth;col){index row*widthcol;double[] label labels.get(index, 0);if(label[0] cIndex[0]){//背景mask.put(row, col, 0);}else{//前景mask.put(row, col, 255);}}}//使用形态学腐蚀操作取出遮罩中的可能干扰正常结果的白点Mat kernel getStructuringElement(MORPH_RECT,new Size(3,3),new Point(-1,-1));erode(mask,mask,kernel);//使用高斯模糊平滑边缘像素GaussianBlur(mask,mask,new Size(3,3),0,0);//执行图像像素融合执行最终的背景替换定义背景颜色double[] bgColor new double[3];bgColor[0] rgbEnd[2];bgColor[1] rgbEnd[1];bgColor[2] rgbEnd[0];//定义一个空的彩色图片Mat result Mat.zeros(src.size(),CvType.CV_8UC3);//下面是背景融合的代码double w 0.0;double b 0, g 0, r 0;double b1 0, g1 0, r1 0;double b2 0, g2 0, r2 0;for(int row 0;rowheight;row){for(int col0;colwidth;col){double[] pix mask.get(row,col);//获取像素值if(pix[0] 255){//前景result.put(row, col, src.get(row,col));}else if(pix[0] 0){//背景result.put(row, col, bgColor);}else{//需要像素融合的部分w pix[0] / 255.0;//权重b1 src.get(row,col)[0];g1 src.get(row,col)[1];r1 src.get(row,col)[2];b2 bgColor[0];g2 bgColor[1];r2 bgColor[2];b b1*wb2*(1.0-w);g g1*wg2*(1.0-w);r r1*wr2*(1.0-w);result.put(row, col, b, g, r);}}}return result;}