[datawhale_3]彩色空间互换

彩色空间互换

1.学习目标

  • 了解相关颜色空间的基础知识
  • 理解彩色空间互换的理论
  • 掌握opencv框架下颜色空间相互API的使用

2.算法理论介绍与资料推荐

1.RGB与灰度图相互

RGB颜色空间基于颜色的加法混色原理,从黑色不断叠加Red,Green,Blue的颜色,最终得到白色

将R、G、B三个通道作为笛卡尔坐标系中的X、Y、Z轴,就得到了一种对于颜色的空间描述,如图:

在这里插入图片描述

对于彩色图转灰度图,有一个很著名的心理学公式
G r a y = R ∗ 0.299 + G ∗ 0.587 + B ∗ 0.114 Gray = R*0.299 + G*0.587 + B*0.114 Gray=R0.299+G0.587+B0.114

2.RGB和HSV互转

HSV 是一种将RGB色彩空间中的点在倒圆锥中的表示方法,即

  • 色相(Hue)
  • 饱和度(Saturation)
  • 明度(Value)

有称HSB(B即, Brightness)

  • 色相(H)是色彩的基本属性,就是平常说的颜色的名称,如红色、黄色等

  • 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值

  • 明度(V)取0-max(计算机中HSV取值范围和存储的长度有关)

HSV模型

在这里插入图片描述

2.2.1RGB2HSV

V ← max ⁡ ( R , G , B ) S ← { V − min ⁡ ( R , G , B ) V  if  V ≠ 0 0  otherwise  H ← { 60 ( G − B ) / ( V − min ⁡ ( R , G , B ) )  if  V = R 120 + 60 ( B − R ) / ( V − min ⁡ ( R , G , B ) ]  if  V = G 240 + 60 ( R − G ) / ( V − min ⁡ ( R , G , B ) )  if  V = B \begin{array}{c} \mathrm{V} \leftarrow \max (\mathrm{R}, \mathrm{G}, \mathrm{B}) \\ \\ \mathrm{S} \leftarrow\left\{\begin{array}{ll} \frac{V-\min (\mathrm{R}, \mathrm{G}, \mathrm{B})}{\mathrm{V}} & \text { if } \mathrm{V} \neq 0 \\ 0 &\text { otherwise } \end{array}\right. \\ \\ \mathrm{H} \leftarrow\left\{\begin{array}{ll} 60(\mathrm{G}-\mathrm{B}) /(\mathrm{V}-\min (\mathrm{R}, \mathrm{G}, \mathrm{B})) & \text { if } \mathrm{V}=\mathrm{R} \\ 120+60(\mathrm{B}-\mathrm{R}) /(\mathrm{V}-\min (\mathrm{R}, \mathrm{G}, \mathrm{B})] & \text { if } \mathrm{V}=\mathrm{G} \\ 240+60(\mathrm{R}-\mathrm{G}) /(\mathrm{V}-\min (\mathrm{R}, \mathrm{G}, \mathrm{B})) & \text { if } \mathrm{V}=\mathrm{B} \end{array}\right. \end{array} Vmax(R,G,B)S{VVmin(R,G,B)0 if V=0 otherwise H60(GB)/(Vmin(R,G,B))120+60(BR)/(Vmin(R,G,B)]240+60(RG)/(Vmin(R,G,B)) if V=R if V=G if V=B

If  H < 0 then  H ← H + 360. On output  0 ≤ V ≤ 1 , 0 ≤ S ≤ 1 , 0 ≤ H ≤ 360 \text{If} \ \mathrm{H}<0 \text{then}\ \mathrm{H} \leftarrow \mathrm{H}+360 . \text{On output}\ 0 \leq \mathrm{V} \leq 1,0 \leq \mathrm{S} \leq 1,0 \leq \mathrm{H} \leq 360 If H<0then HH+360.On output 0V1,0S1,0H360

或者
h = { 0 ∘  if  max ⁡ = min ⁡ 6 0 ∘ × g − b max ⁡ − min ⁡ + 0 ∘ ,  if  max ⁡ = r  and  g ≥ b 6 0 ∘ × g − b max ⁡ − min ⁡ + 36 0 ∘ ,  if  max ⁡ = r  and  g < b 6 0 ∘ × b − r max ⁡ − min ⁡ + 12 0 ∘ ,  if  max ⁡ = g 6 0 ∘ × r − g max ⁡ − min ⁡ + 24 0 ∘ ,  if  max ⁡ = b s = { 0 ,  if  max ⁡ = 0 max ⁡ − min ⁡ max ⁡ = 1 − min ⁡ max ⁡ ,  otherwise  \begin{array}{ll} h=\left\{\begin{array}{ll} 0^{\circ} & \text { if } \max =\min \\ 60^{\circ} \times \frac{g-b}{\max -\min }+0^{\circ}, & \text { if } \max =r \text { and } g \geq b \\ 60^{\circ} \times \frac{g-b}{\max -\min }+360^{\circ}, & \text { if } \max =r \text { and } g<b \\ 60^{\circ} \times \frac{b-r}{\max -\min }+120^{\circ}, & \text { if } \max =g \\ 60^{\circ} \times \frac{r-g}{\max -\min }+240^{\circ}, & \text { if } \max =b \end{array}\right. \\ \\ s=\left\{\begin{array}{ll} 0, & \text { if } \max =0 \\ \frac{\max -\min }{\max }=1-\frac{\min }{\max }, & \text { otherwise } \end{array}\right. \end{array} h=060×maxmingb+0,60×maxmingb+360,60×maxminbr+120,60×maxminrg+240, if max=min if max=r and gb if max=r and g<b if max=g if max=bs={0,maxmaxmin=1maxmin, if max=0 otherwise 

v = m a x v=max v=max

2.2.2HSV2RGB

h i ≡ ⌊ h 60 ⌋ (   m o d   6 ) f = h 60 − h i p = v × ( 1 − s ) q = v × ( 1 − f × s ) t = v × ( 1 − ( 1 − f ) × s ) 对 于 每 个 颜 色 向 量 ( r , g , b ) , ( r , g , b ) = { ( v , t , p ) ,  if  h i = 0 ( q , v , p ) ,  if  h i = 1 ( p , v , t ) ,  if  h i = 2 ( p , q , v ) ,  if  h i = 3 ( t , p , v ) ,  if  h i = 4 ( v , p , q ) ,  if  h i = 5 \begin{aligned} &h_{i} \equiv\left\lfloor\frac{h}{60}\right\rfloor \quad(\bmod 6) \\ &f=\frac{h}{60}-h_{i} \\ &p=v \times(1-s)\\ &q=v \times(1-f \times s)\\ &t=v \times(1-(1-f) \times s)\\ \\ &对于每个颜色向量(r, g, b),\\ &(r, g, b)=\left\{\begin{array}{ll}(v, t, p), & \text { if } h_{i}=0 \\ (q, v, p), & \text { if } h_{i}=1 \\ (p, v, t), & \text { if } h_{i}=2 \\ (p, q, v), & \text { if } h_{i}=3 \\ (t, p, v), & \text { if } h_{i}=4 \\ (v, p, q), & \text { if } h_{i}=5\end{array}\right. \end{aligned} hi60h(mod6)f=60hhip=v×(1s)q=v×(1f×s)t=v×(1(1f)×s)r,g,b),(r,g,b)=(v,t,p),(q,v,p),(p,v,t),(p,q,v),(t,p,v),(v,p,q), if hi=0 if hi=1 if hi=2 if hi=3 if hi=4 if hi=5

3.基于opencv的实现

函数cvtColor()

void cvtColor(InputArray src, //输入图片
              OutputArray dst, //输出图片
              int code,        // 颜色空间转换标示符
              int dstCn=0)     // 目标图像的通道数,该参数为0时,目标图像根据源图像的通道数和具体操                                   作进行决定
//-----------------------------------------------
code: 
    1.注意RGB色彩空间默认的通道顺序为BGR

3.1实现示例(c++)

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
	Mat img = imread("C:/Users/Administrator/Desktop/opencv/test1.jpg");
	if (img.empty())
	{
		cout << "无法读取图像" << endl;
		return 0;
	}
	//RGB2GHSV
	Mat dstImage;
	cvtColor(img, dstImage,COLOR_RGB2HSV);
	imshow("RGB2HSV",dstImage);
	//RGB2GRAY
	cvtColor(img, dstImage, COLOR_RGB2GRAY);
	imshow("RGB2GRAY", dstImage);

	waitKey(0);
	return 0;
}

3.2进阶实现(根据原理自己实现)

3.2.1.RGB2GRAY

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat RGB2GRAY(Mat src, bool accelerate = false) 
{
    /*自定义转换
    @src 输入图像
    @返回dst  输出图像
    */
	CV_Assert(src.channels() == 3);
	Mat dst = Mat::zeros(src.size(), CV_8UC1);
	Vec3b rgb;
	int r = src.rows;
	int c = src.cols;

	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
		{
			rgb = src.at<Vec3b>(i, j);
			uchar B = rgb[0]; uchar G = rgb[1]; uchar R = rgb[2];
			if (accelerate = false)
				dst.at<uchar>(i, j) = R * 0.299 + G * 0.587 + B * 0.114; //原式
			else
				dst.at<uchar>(i, j) = (R * 4898 + G * 9618 + B * 1868) >> 14; //加速

		}
	return dst;
}

	int main(int argc, char* argv[])
	{
		Mat img = imread("C:/Users/Administrator/Desktop/opencv/test1.jpg");
		if (img.empty())
		{
			cout << "无法读取图像" << endl;
			return 0;
		}

		Mat dst, dst1;

		//opencv自带
		double t2 = (double)getTickCount(); //测时间
		cvtColor(img, dst1, COLOR_RGB2GRAY);
		t2 = (double)getTickCount() - t2;
		double time2 = (t2 * 1000.) / ((double)getTickFrequency());
		cout << "Opencv_rgb2gray=" << time2 << " ms. " << endl;

		//RGB2GRAY
		double t1 = (double)getTickCount(); //测时间
		dst = RGB2GRAY(img, true);
		t1 = (double)getTickCount() - t1;
		double time1 = (t1 * 1000.) / ((double)getTickFrequency());
		cout << "My_rgb2gray=" << time1 << " ms. " << endl;

		imshow("img", img);
		imshow("My_rgb2gray", dst);
		imshow("Opencv_rgb2gray", dst1);
		waitKey(0);
		return 0;
	}
3.2.2.RGB2HCV/HSV2RGB
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat RGB2HSV(Mat src)
{
	int row = src.rows;
	int col = src.cols;
	Mat dst(row, col, CV_32FC3);
	for(int i=0;i<row;i++)
		for (int j = 0; j < col; j++)
		{
			float b = src.at<Vec3b>(i, j)[0] / 255.0;
			float g = src.at<Vec3b>(i, j)[1] / 255.0;
			float r = src.at<Vec3b>(i, j)[2] / 255.0;

			float minn = min(r, min(g, b));
			float maxx = max(r, max(g, b));
		
			float v, h, s;
			v = maxx;

			if (v != 0)
				s = (v - minn) / v;
			else
				s = 0;
			
			if (v == r )
				h = 60*(g - b) / (v-minn);
			else if (v == g)
				h = 120 + 60*(b - r) / (v-minn);
			else if (v == b)
				h = 244 + 60*(r - g) / (v-minn);
			else
				h = 0;
			
			if (h < 0)
				h += 360;

			dst.at<Vec3f>(i, j)[0] = h;
			dst.at<Vec3f>(i, j)[1] = s;
			dst.at<Vec3f>(i, j)[2] = v;
		}
	return dst;
}

Mat HSV2RGB(Mat src) {
	int row = src.rows;
	int col = src.cols;
	Mat dst(row, col, CV_8UC3);
	float r, g, b, h, s, v;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			h = src.at<Vec3f>(i, j)[0];
			s = src.at<Vec3f>(i, j)[1];
			v = src.at<Vec3f>(i, j)[2];
			if (s == 0) 
				r = g = b = v;
			else {
				h /= 60;
				int offset = floor(h);
				float f = h - offset;
				float p = v * (1 - s);
				float q = v * (1 - s * f);
				float t = v * (1 - s * (1 - f));
				switch (offset)
				{
				case 0: r = v; g = t; b = p; break;
				case 1: r = q; g = v; b = p; break;
				case 2: r = p; g = v; b = t; break;
				case 3: r = p; g = q; b = v; break;
				case 4: r = t; g = p; b = v; break;
				case 5: r = v; g = p; b = q; break;
				default:
					break;
				}
			}
			dst.at<Vec3b>(i, j)[0] = int(b * 255);
			dst.at<Vec3b>(i, j)[1] = int(g * 255);
			dst.at<Vec3b>(i, j)[2] = int(r * 255);
		}
	}
	return dst;
}

	int main(int argc, char* argv[])
	{
		Mat img = imread("C:/Users/Administrator/Desktop/opencv/test1.jpg");
		if (img.empty())
		{
			cout << "无法读取图像" << endl;
			return 0;
		}

		Mat dst = RGB2HSV(img);
		Mat dst1 = HSV2RGB(dst);

		imshow("img", img);
		imshow("My_rgb2hsv", dst);
		imshow("My_hsv2rgb", dst1);
		waitKey(0);
		return 0;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值