【画像処理100本ノックに挑戦】Q.21. ヒストグラム正規化

# 使用したライブラリ
[【画像処理100本ノック】独自の画像入出力クラスを作る](https://qiita.com/jajagacchi/items/834e8425b84f94df8a49)

# Q.21. ヒストグラム正規化
> ヒストグラム正規化を実装せよ。

これも簡単です。

```c++
int main()
{
	PPM ppm("imori_dark.pnm");
	int width = ppm.Get_width();
	int height = ppm.Get_height();
	
	int N = 256;
	std::vector<int> hist(N);
	for (int n = 0; n < N; n++)
	{
		hist[n] = 0;
	}

	int c = 256, d = 0;
	for(int j=0; j<height; j++)
		for (int i = 0; i < width; i++)
		{
			int minval = std::min({ ppm(i, j, 'r') ,ppm(i, j, 'g') ,ppm(i, j, 'b') });
			int maxval = std::max({ ppm(i, j, 'r') ,ppm(i, j, 'g') ,ppm(i, j, 'b') });
			if (minval < c) c = minval;
			if (maxval > d) d = maxval;
			
		}

	PPM ppm2(width,height);
	int a = 0, b = 255;
	for (int j = 0; j < height; j++)
		for (int i = 0; i < width; i++)
		{
			ppm2(i, j, 'r') = (double)(b - a) / (d - c) * (ppm(i, j, 'r')-c) + a;
			ppm2(i, j, 'g') = (double)(b - a) / (d - c) * (ppm(i, j, 'g') - c) + a;
			ppm2(i, j, 'b') = (double)(b - a) / (d - c) * (ppm(i, j, 'b') - c) + a;
			hist[ppm2(i, j, 'r')]++;
			hist[ppm2(i, j, 'g')]++;
			hist[ppm2(i, j, 'b')]++;
		}
	ppm2.Flush("out.ppm");

	for (int n = 0; n < N; n++)
	{
		std::cout << n << " " << hist[n] << std::endl;
	}


	return 0;
}
```

![imori_dark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/634a7c0f-cdac-b1e2-6f5e-dcb4451f7b28.png) ![out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/571b80eb-d18d-7303-aaa8-e438671da3ca.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/96665927-edc1-8d25-9b48-085806bfc55b.png)

# おまけ(HSV変換)
画像明るくするならHSV変換で出来ないのかな？と思って試してみました。
RGB->HSVと変換してVを$\alpha>1$倍するだけ。

```c++
struct HSV
{
	double h, s, v;
};
struct RGB
{
	RGB(int r, int g, int b)
	{
		this->r = r;
		this->g = g;
		this->b = b;
	}
	int r, g, b;
};

HSV RGB2HSV(const RGB& rgb)
{
	HSV hsv;
	int r = rgb.r;
	int g = rgb.g;
	int b = rgb.b;
	int Max = std::max({ r, g, b });
	int Min = std::min({ r, g, b });
	if (Min == Max) hsv.h = 0;
	else if (Min == b) hsv.h = 60 * (g - r) / (double)(Max - Min) + 60;
	else if (Min == r) hsv.h = 60 * (b - g) / (double)(Max - Min) + 180;
	else if (Min == g) hsv.h = 60 * (r - b) / (double)(Max - Min) + 300;
	hsv.v = Max / 255.;
	hsv.s = (Max - Min) / 255.;
	return hsv;
}
RGB HSV2RGB(const HSV& hsv)
{
	double r, g, b;
	double h = hsv.h;
	double s = hsv.s;
	double v = hsv.v;
	double c = s;
	double h2 = h / 60.;
	double x = c * (1 - fabs(fmod(h2, 2) - 1));

	if (0 <= h2 && h2 < 1) r = c, g = x, b = 0;
	else if (1 <= h2 && h2 < 2) r = x, g = c, b = 0;
	else if (2 <= h2 && h2 < 3) r = 0, g = c, b = x;
	else if (3 <= h2 && h2 < 4) r = 0, g = x, b = c;
	else if (4 <= h2 && h2 < 5) r = x, g = 0, b = c;
	else if (5 <= h2 && h2 < 6) r = c, g = 0, b = x;
	else r = g = b = 0;
	r += (v - c);
	g += (v - c);
	b += (v - c);

	return RGB(r * 255, g * 255, b * 255);
}

int main()
{
	PPM ppm("imori_dark.pnm");
	int width = ppm.Get_width();
	int height = ppm.Get_height();
	
	int N = 256;
	std::vector<int> hist(N);
	for (int n = 0; n < N; n++)
	{
		hist[n] = 0;
	}

	double vmax = 0;
	for (int j = 0; j < height; j++)
		for (int i = 0; i < width; i++)
		{
			HSV hsv = RGB2HSV(RGB(ppm(i,j,'r'), ppm(i, j, 'g'), ppm(i, j, 'b')));
			if (hsv.v > vmax) vmax = hsv.v;
		}
	PPM ppm2(width, height);
	for (int j = 0; j < height; j++)
		for (int i = 0; i < width; i++)
		{
			HSV hsv = RGB2HSV(RGB(ppm(i, j, 'r'), ppm(i, j, 'g'), ppm(i, j, 'b')));
			hsv.v *= 1. / vmax;
			RGB rgb = HSV2RGB(hsv);
			ppm2(i, j, 'r') = rgb.r;
			ppm2(i, j, 'g') = rgb.g;
			ppm2(i, j, 'b') = rgb.b;
			hist[ppm2(i, j, 'r')]++;
			hist[ppm2(i, j, 'g')]++;
			hist[ppm2(i, j, 'b')]++;
		}
	
	ppm2.Flush("out.ppm");

	for (int n = 0; n < N; n++)
	{
		std::cout << n << " " << hist[n] << std::endl;
	}


	return 0;
}
```
![imori_dark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/634a7c0f-cdac-b1e2-6f5e-dcb4451f7b28.png) ![out2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/a7298ca7-b1c4-c5e0-8902-391618849ca7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/ea299785-ee7c-193a-b019-fe46be702746.png)

元のヒストグラムより少し広がっていますね。正規化ほどの効果はありませんでした。