C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)详解

时间:2022-05-17 03:21:50

本文实例讲述了C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)。分享给大家供大家参考,具体如下:

今天刚好老师要办点事情,老师唯一的一张证件照是蓝色的,但是需要的底色是白色的,于是乎,好久不折腾的PS也忘记了,还好旁边的刚来的小学弟懂一点,

在那里慢慢的帮老师一点点的处理,PS在边缘的地方效果还真不咋地,确实是一门技术活。

于是我就想OpenCV能不能实现呢?一搜百度第一篇就是,但是人家转成红色,然后我又对HSV颜色空间不是很懂,最后在一个学习群里

但是文中未对HSV那一块做出解释,可能是我太菜了

贴出去问了下,一位优秀的本科生帮我清晰解答了,汗颜

主要步骤为:

1.把RGB图像转换到HSV空间

2.取背景的一小块20*20,计算蓝色背景的平均色调和饱和度

3.设置阈值,取出蓝色背景替换为红色背景

4.把HSV图像转换会RGB空间

5.滤波器去除边缘效应

具体代码为:

  1. // change_color.cpp : 定义控制台应用程序的入口点。
  2. //证件照从蓝色底换成红色底
  3. //#include "stdafx.h"
  4. #include <iostream>
  5. #include <opencv2\core\core.hpp>
  6. #include <opencv2\highgui\highgui.hpp>
  7. #include <opencv2\imgproc\imgproc.hpp>
  8. using namespace cv;
  9. using namespace std;
  10. int main()
  11. {
  12. char *origin="Original";
  13. char *window="Image";
  14. char *str="C:\\Users\\ltc\\Desktop\\nihao.jpg";
  15. namedWindow(origin,1);
  16. namedWindow(window,1);
  17. Mat image=imread(str);
  18. if(!image.data)
  19. {
  20. cout<<"图像载入出现问题"<<endl;
  21. return 0;
  22. }
  23. Mat roi=image(Rect(20,20,20,20));
  24. Mat hsvImg;
  25. cvtColor(image, hsvImg, CV_BGR2HSV); //将图像转换到HSV颜色空间
  26. //分离HSV空间,v[0]为H色调,v[1]为S饱和度,v[2]为v灰度
  27. vector<Mat> v;
  28. split(hsvImg,v);
  29. Mat roiH=v[0](Rect(20,20,20,20));
  30. Mat roiS=v[1](Rect(20,20,20,20));
  31. int SumH=0;
  32. int SumS=0;
  33. int avgH, avgS;//蓝底的平均色调和平均饱和度
  34. //取一块蓝色背景,计算出它的平均色调和平均饱和度
  35. for(int i=0; i<20; i++)
  36. {
  37. for(int j=0; j<20; j++)
  38. {
  39. /*SumH=SumH+roiH(i,j);*/
  40. SumH=int(roiH.at<uchar>(j,i))+SumH;
  41. SumS=int(roiS.at<uchar>(j,i))+SumS;
  42. }
  43. }
  44. avgH=SumH/400;
  45. avgS=SumS/400;
  46. //遍历整个图像
  47. int nl=hsvImg.rows;
  48. int nc=hsvImg.cols;
  49. int step=10;
  50. for(int j=0; j<nl; j++)
  51. {
  52. for(int i=0; i<nc; i++)
  53. {
  54. //以H.S两个通道做阈值分割,把蓝色替换成红色
  55. if((v[0].at<uchar>(j,i))<=(avgH+5) && v[0].at<uchar>(j,i)>=(avgH-5)
  56. &&(v[1].at<uchar>(j,i))<=(avgS+40) && v[1].at<uchar>(j,i)>=(avgS-40))
  57. {
  58. //cout<<int(v[0].at<uchar>(j,i))<<endl;
  59. //红色底
  60. //v[0].at<uchar>(j,i)=0;
  61. //白色底
  62. v[0].at<uchar>(j,i)=0;
  63. v[1].at<uchar>(j,i)=0; //V[0]和V[1]全调成0就是变成白色
  64. //绿色底
  65. //v[0].at<uchar>(j,i)=60;
  66. //蓝色底
  67. //v[0].at<uchar>(j,i)=120;
  68. /*cout<<int(v[0].at<uchar>(j,i))<<endl;*/
  69. }
  70. }
  71. }
  72. Mat finImg;
  73. merge(v,finImg);
  74. Mat rgbImg;
  75. cvtColor(finImg,rgbImg, CV_HSV2BGR); //将图像转换回RGB空间
  76. imshow(origin,image);
  77. imshow(window,rgbImg);
  78. //加个滤波把边缘部分的值滤掉(此处应该用低通滤波器,但感觉不太好,还是不用了。)
  79. Mat result;
  80. GaussianBlur(rgbImg,result,Size(3,3),0.5);
  81. imshow(window,result);
  82. imwrite("nihaoWhite.jpg",result);
  83. waitKey(0);
  84. //system("pause");
  85. return 0;
  86. }
  87. ////遍历整个图像
  88. //int nl=hsvImg.rows;
  89. //int nc=hsvImg.cols * hsvImg.channels();
  90. //for(int j=0; j<nl; j++)
  91. //{
  92. // uchar *data=hsvImg.ptr<uchar>(j);
  93. // for(int i=0; i<nc; i++)
  94. // {
  95. // cout<<int(data[i])<<" ";
  96. // }
  97. //}

这里面主要说明一下:

HSV模型

倒锥形模型:

C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)详解

这个模型就是按色彩、深浅、明暗来描述的。

H是色彩

S是深浅, S = 0时,只有灰度

V是明暗,表示色彩的明亮程度,但与光强无直接联系,(意思是有一点点联系吧)。

C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)详解

在这个程序里

色调主要是由V[0]来控制的

hsv是一个360度的模型 每个角度代表一种颜色

0度是红色

120度是绿色

240度是蓝色

但是OpenCV里最大值是255 所以它会对色调除以2,就是最大值是180

绿色对应的让它等于60    蓝色对应的就是120

换不同的背景只需要改动:

  1. //红色底
  2. v[0].at<uchar>(j,i)=0;
  3. //白色底
  4. v[0].at<uchar>(j,i)=0;
  5. v[1].at<uchar>(j,i)=0; //V[0]和V[1]全调成0就是变成白色
  6. //绿色底
  7. v[0].at<uchar>(j,i)=60;
  8. //蓝色底
  9. v[0].at<uchar>(j,i)=120;

改动的位置就不需要说明了吧!这个方法的效果确实不错,大赞!

毕竟是老师的图片,不能轻易放出来,网上的也不能随便用吧!哈哈

那就放张我最爱的崩坏3吧!

C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)详解

附录

提取图像中指定颜色的像素区域

  1. #include<iostream>
  2. #include<opencv2/core/core.hpp>
  3. #include<opencv2/imgproc/imgproc.hpp>
  4. #include<opencv2/highgui/highgui.hpp>
  5. using namespace cv;
  6. class ColorDetector
  7. {
  8. private:
  9. //最小可接受距离
  10. int minDist;
  11. //目标色
  12. cv::Vec3b target;
  13. //结果图像
  14. cv::Mat result;
  15. //计算与目标颜色的距离
  16. int getDistance(cv::Vec3b color)
  17. {
  18. return abs(color[0] - target[0]) + abs(color[1] - target[1]) + abs(color[2] - target[2]);
  19. }
  20. public:
  21. //空构造函数
  22. ColorDetector() :minDist(100)
  23. {
  24. //初始化默认参数
  25. target[0] = target[1] = target[2] = 0;
  26. }
  27. void setColorDistanceThreshold(int distance);
  28. int getColorDistanceThreshold() const;
  29. void setTargetColor(unsigned char red, unsigned char green, unsigned char blue);
  30. void setTargetColor(cv::Vec3b color);
  31. cv::Vec3b getTargetColor() const;
  32. cv::Mat ColorDetector::process(const cv::Mat &image);
  33. };
  34. //设置色彩距离阈值,阈值必须是正的,否则设为0
  35. void ColorDetector::setColorDistanceThreshold(int distance)
  36. {
  37. if (distance < 0)
  38. distance = 0;
  39. minDist = distance;
  40. }
  41. //获取色彩距离阈值
  42. int ColorDetector::getColorDistanceThreshold() const
  43. {
  44. return minDist;
  45. }
  46. //设置需检测的颜色
  47. void ColorDetector::setTargetColor(unsigned char red, unsigned char green, unsigned char blue)
  48. {
  49. //BGR顺序
  50. target[2] = red;
  51. target[1] = green;
  52. target[0] = blue;
  53. }
  54. //设置需检测的颜色
  55. void ColorDetector::setTargetColor(cv::Vec3b color)
  56. {
  57. target = color;
  58. }
  59. //获取需检测的颜色
  60. cv::Vec3b ColorDetector::getTargetColor() const
  61. {
  62. return target;
  63. }
  64. cv::Mat ColorDetector::process(const cv::Mat &image)//核心的处理方法
  65. {
  66. //按需重新分配二值图像
  67. //与输入图像的尺寸相同,但是只有一个通道
  68. result.create(image.rows, image.cols, CV_8U);
  69. //得到迭代器
  70. cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>();
  71. cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>();
  72. cv::Mat_<uchar>::iterator itout = result.begin<uchar>();
  73. for (; it != itend; ++it, ++itout)//处理每个像素
  74. {
  75. //计算离目标颜色的距离
  76. if (getDistance(*it) < minDist)
  77. {
  78. *itout = 255;
  79. }
  80. else
  81. {
  82. *itout = 0;
  83. }
  84. }
  85. return result;
  86. }
  87. int _tmain(int argc, _TCHAR* argv[])
  88. {
  89. //1.创建图像处理的对象
  90. ColorDetector cdetect;
  91. //2.读取输入图像
  92. cv::Mat image = cv::imread("boldt.jpg");
  93. if (!image.data)
  94. {
  95. return 0;
  96. }
  97. //3.设置输入参数
  98. cdetect.setTargetColor(130, 190, 230);//蓝天的颜色
  99. cv::namedWindow("result");
  100. //4.处理并显示结果
  101. cv::imshow("result", cdetect.process(image));
  102. cv::waitKey();
  103. return 0;
  104. }

希望本文所述对大家C++程序设计有所帮助。

原文链接:https://blog.csdn.net/qq_37059483/article/details/77840976