OpenCV——画像のコントラスト、明るさ、彩度を調整する

44129 ワード

一、画像のコントラストと明るさの調整
1、原理:
  • f(row, col):オリジナル画像の画素.
  • g(row, col):調整後の画像の画素.
  • a(a>0:利得(gain)と呼ばれ、画像のコントラストを制御するためによく用いられるが、その値範囲は一般的に0.0-3.0
  • である.
  • b:バイアス(bias)と呼ばれ、画像の輝度を制御するためによく用いられる.
  • g(row, col) = a*f(row, col) + b:元の画像に従ってコントラスト輝度を調整する式.
  • new_img.at (row, col)[c]:opencvは、ピクチャの各画素の構文にアクセスする.
  • saturate_cast():オーバーフロー防止.演算が完了すると、結果は負になり、0に変わり、結果は255を超え、255になります.

  • 2、C++OpenCVコアコード:
    元のピクチャの各画素を巡回し,R,G,Bをそれぞれ式で変換する.
    void contrast_bright (int, void*)
    {
    	contrastValue_f = 0.1 * contrastValue; //              ,  contrastValue     。
    	for (int row = 0; row < img.rows; row++)
    	{
    		for (int col = 0; col < img.cols; col++)
    		{
    			for (int c = 0; c < 3; c++) {
    				new_img.at<Vec3b> (row, col)[c] = saturate_cast<uchar>(contrastValue_f * (img.at<Vec3b> (row, col)[c]) + brightValue);  // g(x,y) = af(x,y) + b; a       ,b     
    			}
    		}
    	}
    	imshow ("Effect Image", new_img);
    }
    
  • Mat.at (row, col)[c]:ピクチャ画素を巡回する方法.https://docs.opencv.org/3.4/d5/d98/tutorial_mat_operations.html
  • saturate_cast:オーバーフロー防止.

  • 二、画像の彩度調整
    ネット上では画像の飽和度調整に関するアルゴリズムが多く、どちらを選ぶか分かりません.だから、どの効果がいいか試してみましょう.ここで、参考にしました.https://blog.csdn.net/u012198575/article/details/82985482この文章が言及したアルゴリズムは,アルゴリズムの構想がはっきりしている.
    1、Photoshop飽和度調整思想(PSかどうか私にもわかりません~):
  • は、RGBに関する各画素点の最大値、最小値を算出する.
  • deltaを2値の差/255とし、valueを2値の和/255とする.
  • の2値の差deltaは0で動作しない、すなわち、この画素点をスキップする.そうでなければ、次の操作を行います:
  • RGB画像をHSL画像(Hue:色彩,Saturability:飽和度,Light:輝度)
  • に変換する.
  • light=value/2、light<0.5の場合sat=delta/value;そうでない場合:sat=delta/(2-value);
  • 最後に、インクリメンタル判定によりどのような処理を行うかを判断し、変換後の新たなRGB値を新たなピクチャに格納する.

  • 2、C++コアコード:
    void saturability (int, void*)
    {
    	float increment = (saturation - 80) * 1.0 / max_increment;
    	for (int col = 0; col < img.cols; col++)
    	{
    		for (int row = 0; row < img.rows; row++)
    		{
    			// R,G,B            2,1,0
    			uchar r = img.at<Vec3b> (row, col)[2];		
    			uchar g = img.at<Vec3b> (row, col)[1];
    			uchar b = img.at<Vec3b> (row, col)[0];
    
    			float maxn = max (r, max (g, b));
    			float minn = min (r, min (g, b));
    
    			float delta, value;
    			delta = (maxn - minn) / 255;
    			value = (maxn + minn) / 255;
    
    			float new_r, new_g, new_b;
    
    			if (delta == 0)		 //    0     ,      
    			{
    				new_img.at<Vec3b> (row, col)[0] = new_b;
    				new_img.at<Vec3b> (row, col)[1] = new_g;
    				new_img.at<Vec3b> (row, col)[2] = new_r;
    				continue;
    			}
    
    			float light, sat, alpha;
    			light = value / 2;
    
    			if (light < 0.5)
    				sat = delta / value;
    			else
    				sat = delta / (2 - value);
    
    			if (increment >= 0)
    			{
    				if ((increment + sat) >= 1)
    					alpha = sat;
    				else
    				{
    					alpha = 1 - increment;
    				}
    				alpha = 1 / alpha - 1;
    				new_r = r + (r - light * 255) * alpha;
    				new_g = g + (g - light * 255) * alpha;
    				new_b = b + (b - light * 255) * alpha;
    			}
    			else
    			{
    				alpha = increment;
    				new_r = light * 255 + (r - light * 255) * (1 + alpha);
    				new_g = light * 255 + (g - light * 255) * (1 + alpha);
    				new_b = light * 255 + (b - light * 255) * (1 + alpha);
    			}
    			new_img.at<Vec3b> (row, col)[0] = new_b;
    			new_img.at<Vec3b> (row, col)[1] = new_g;
    			new_img.at<Vec3b> (row, col)[2] = new_r;
    		}
    	}
    	imshow ("Effect Image", new_img);
    }
    

    三、OpenCV実現の画像のコントラスト、明るさ、飽和度の完全なコード
    #include
    #include
    #include
    #include
    #include
    #include 
    
    using namespace std;
    using namespace cv;
    
    int contrastValue;	//     
    float contrastValue_f; //          , contrastValue       
    int brightValue;   //    
    int saturation;	//    
    const int max_increment = 200;
    Mat img, new_img;	   //img:    ; new_img:       ;
    
    void contrast_bright (int, void*);
    void saturability (int, void*);
    
    //         
    void contrast_bright (int, void*)
    {
    	contrastValue_f = 0.1 * contrastValue;
    	for (int row = 0; row < img.rows; row++)
    	{
    		for (int col = 0; col < img.cols; col++)
    		{
    			for (int c = 0; c < 3; c++) {
    				new_img.at<Vec3b> (row, col)[c] = saturate_cast<uchar>(contrastValue_f * (img.at<Vec3b> (row, col)[c]) + brightValue);  // g(x,y) = af(x,y) + b; a       ,b     
    			}
    		}
    	}
    	imshow ("Effect Image", new_img);
    }
    
    //     
    void saturability (int, void*)
    {
    	float increment = (saturation - 80) * 1.0 / max_increment;
    	for (int col = 0; col < img.cols; col++)
    	{
    		for (int row = 0; row < img.rows; row++)
    		{
    			// R,G,B            2,1,0
    			uchar r = img.at<Vec3b> (row, col)[2];		
    			uchar g = img.at<Vec3b> (row, col)[1];
    			uchar b = img.at<Vec3b> (row, col)[0];
    
    			float maxn = max (r, max (g, b));
    			float minn = min (r, min (g, b));
    
    			float delta, value;
    			delta = (maxn - minn) / 255;
    			value = (maxn + minn) / 255;
    
    			float new_r, new_g, new_b;
    
    			if (delta == 0)		 //    0     ,      
    			{
    				new_img.at<Vec3b> (row, col)[0] = new_b;
    				new_img.at<Vec3b> (row, col)[1] = new_g;
    				new_img.at<Vec3b> (row, col)[2] = new_r;
    				continue;
    			}
    
    			float light, sat, alpha;
    			light = value / 2;
    
    			if (light < 0.5)
    				sat = delta / value;
    			else
    				sat = delta / (2 - value);
    
    			if (increment >= 0)
    			{
    				if ((increment + sat) >= 1)
    					alpha = sat;
    				else
    				{
    					alpha = 1 - increment;
    				}
    				alpha = 1 / alpha - 1;
    				new_r = r + (r - light * 255) * alpha;
    				new_g = g + (g - light * 255) * alpha;
    				new_b = b + (b - light * 255) * alpha;
    			}
    			else
    			{
    				alpha = increment;
    				new_r = light * 255 + (r - light * 255) * (1 + alpha);
    				new_g = light * 255 + (g - light * 255) * (1 + alpha);
    				new_b = light * 255 + (b - light * 255) * (1 + alpha);
    			}
    			new_img.at<Vec3b> (row, col)[0] = new_b;
    			new_img.at<Vec3b> (row, col)[1] = new_g;
    			new_img.at<Vec3b> (row, col)[2] = new_r;
    		}
    	}
    	imshow ("Effect Image", new_img);
    }
    
    int main ()
    {
    	img = imread ("test.jpg");		//     ,    Mat    img  
    	new_img = Mat::zeros (img.size (), img.type ());    //           
    
    	contrastValue = 1;	//      
    	brightValue = 1;	//     
    	saturation = 10;	//      
    
    	namedWindow ("Effect Image", WINDOW_NORMAL);		//        
    
    	createTrackbar ("Contrast:", "Effect Image", &contrastValue, 100, contrast_bright);	//         
    	createTrackbar ("Brightness:", "Effect Image", &brightValue, 200, contrast_bright);	//        
    	createTrackbar ("Saturability:", "Effect Image", &saturation, 200, saturability); //         
    
    	//     ,       ,   userdata  0
    	contrast_bright (contrastValue, 0);
    	contrast_bright (brightValue, 0);
    	saturability (saturation, 0);
    	
    	cv::waitKey (0);
    	return 0;
    }