OpenCV C++ 圖像處理之自動色階


自動色階

第一步,分別統計各通道(紅/綠/藍)的直方圖。

第二步,分別計算各通道按照給定的參數所確定的上下限值。什么意思呢,比如對於藍色通道,我們從色階0開始向上累加統計直方圖,當累加值大於LowCut所有像素數時,以此時的色階值計為BMin。然后從色階255開始向下累計直方圖,如果累加值大於HighCut所有像素時,以此時的色階值計為BMax。

第三步,按照我們剛剛計算出的MinBlue/MaxBlue構建一個隱射表,隱射表的規則是,對於小於MinBlue的值,則隱射為0(實際上這句話也不對,隱射為多少是和那個自動顏色校正選項對話框中的陰影所設定的顏色有關,默認情況下是黑色,對應的RGB分量都為0,所以我們這里就隱射為0,有興趣你們也可以指定為其他的參數),對於大於MaxBlue的值,則隱射為255(同理,這個值和高光的顏色設置有關),對於介於MinBlue和MaxBlue之間的值,則進行線性隱射,默認是隱射為0到255之間(當然實際是和我們的暗調和高光的設置有關,並且這里其實也不是線性隱射,是有一個Gamma校正,為了簡便,用線性替代效果也沒太大的問題)。

最后一步,對各通道圖像數據進行隱射。

 1 // AutoLevel.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。  2 //  3 
 4 #include <iostream>
 5 #include<opencv2\core\core.hpp>
 6 #include<opencv2\highgui\highgui.hpp>
 7 #include<opencv2\imgproc\imgproc.hpp>
 8 #include<iostream>
 9 #include<vector>
 10 #include <algorithm>
 11 using namespace cv;  12 
 13 void AutoLevelsAdjust(cv::Mat& src, cv::Mat& dst)  14 {  15     CV_Assert(!src.empty() && src.channels() == 3);  16 
 17     //統計灰度直方圖
 18     int BHist[256] = { 0 };    //B分離
 19     int GHist[256] = { 0 };    //G分量
 20     int RHist[256] = { 0 };    //R分量
 21     cv::MatIterator_<Vec3b> its, ends;  22     for (its = src.begin<Vec3b>(), ends = src.end<Vec3b>(); its != ends; its++)  23  {  24         BHist[(*its)[0]]++;  25         GHist[(*its)[1]]++;  26         RHist[(*its)[2]]++;  27  }  28 
 29     //設置LowCut和HighCut
 30     float LowCut = 0.5;  31     float HighCut = 0.5;  32 
 33     //根據LowCut和HighCut查找每個通道最大值最小值
 34     int BMax = 0, BMin = 0;  35     int GMax = 0, GMin = 0;  36     int RMax = 0, RMin = 0;  37 
 38     int TotalPixels = src.cols * src.rows;  39     float LowTh = LowCut * 0.01 * TotalPixels;  40     float HighTh = HighCut * 0.01 * TotalPixels;  41 
 42     //B通道查找最小最大值
 43     int sumTempB = 0;  44     for (int i = 0; i < 256; i++)  45  {  46         sumTempB += BHist[i];  47         if (sumTempB >= LowTh)  48  {  49             BMin = i;  50             break;  51  }  52  }  53     sumTempB = 0;  54     for (int i = 255; i >= 0; i--)  55  {  56         sumTempB += BHist[i];  57         if (sumTempB >= HighTh)  58  {  59             BMax = i;  60             break;  61  }  62  }  63 
 64     //G通道查找最小最大值
 65     int sumTempG = 0;  66     for (int i = 0; i < 256; i++)  67  {  68         sumTempG += GHist[i];  69         if (sumTempG >= LowTh)  70  {  71             GMin = i;  72             break;  73  }  74  }  75     sumTempG = 0;  76     for (int i = 255; i >= 0; i--)  77  {  78         sumTempG += GHist[i];  79         if (sumTempG >= HighTh)  80  {  81             GMax = i;  82             break;  83  }  84  }  85 
 86     //R通道查找最小最大值
 87     int sumTempR = 0;  88     for (int i = 0; i < 256; i++)  89  {  90         sumTempR += RHist[i];  91         if (sumTempR >= LowTh)  92  {  93             RMin = i;  94             break;  95  }  96  }  97     sumTempR = 0;  98     for (int i = 255; i >= 0; i--)  99  { 100         sumTempR += RHist[i]; 101         if (sumTempR >= HighTh) 102  { 103             RMax = i; 104             break; 105  } 106  } 107 
108     //對每個通道建立分段線性查找表 109     //B分量查找表
110     int BTable[256] = { 0 }; 111     for (int i = 0; i < 256; i++) 112  { 113         if (i <= BMin) 114             BTable[i] = 0; 115         else if (i > BMin && i < BMax) 116             BTable[i] = cvRound((float)(i - BMin) / (BMax - BMin) * 255); 117         else
118             BTable[i] = 255; 119  } 120 
121     //G分量查找表
122     int GTable[256] = { 0 }; 123     for (int i = 0; i < 256; i++) 124  { 125         if (i <= GMin) 126             GTable[i] = 0; 127         else if (i > GMin && i < GMax) 128             GTable[i] = cvRound((float)(i - GMin) / (GMax - GMin) * 255); 129         else
130             GTable[i] = 255; 131  } 132 
133     //R分量查找表
134     int RTable[256] = { 0 }; 135     for (int i = 0; i < 256; i++) 136  { 137         if (i <= RMin) 138             RTable[i] = 0; 139         else if (i > RMin && i < RMax) 140             RTable[i] = cvRound((float)(i - RMin) / (RMax - RMin) * 255); 141         else
142             RTable[i] = 255; 143  } 144 
145     //對每個通道用相應的查找表進行分段線性拉伸
146     cv::Mat dst_ = src.clone(); 147     cv::MatIterator_<Vec3b> itd, endd; 148     for (itd = dst_.begin<Vec3b>(), endd = dst_.end<Vec3b>(); itd != endd; itd++) 149  { 150         (*itd)[0] = BTable[(*itd)[0]]; 151         (*itd)[1] = GTable[(*itd)[1]]; 152         (*itd)[2] = RTable[(*itd)[2]]; 153  } 154     dst = dst_; 155 } 156 
157 int main() 158 { 159     Mat image = imread("E:\\picture\\wutian.jpg"); 160     Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC1); 161  AutoLevelsAdjust(image, dst); 162     imshow("src", image); 163     imshow("dst", dst); 164     while (char(waitKey(1)) != 'q') {} 165 }

在這里插入圖片描述

自動色階用來做去霧,還是最為穩定的,雖然現在有很多種其他增強方法,例如暗通道去霧,優化對比度去霧,基於Color-Lines的去霧,但是這些算法還不是很穩定,當先驗知識失效時,處理失真比較嚴重。但自動色階相對就比較穩定。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM