自動カラースケール
最初のステップは、各チャネル(赤/緑/青)のヒストグラムをそれぞれカウントすることです。
2番目のステップは、指定されたパラメーターに従って各チャネルの上限と下限を計算することです。どういう意味ですか?たとえば、青チャンネルの場合、統計ヒストグラムをレベル0から上方向に累積し、累積値がLowCut のピクセル数よりも大きい場合、このときのレベル値をBMinとしてカウントします。次に、ヒストグラムを階調レベル255から下方向に累積し、累積値がHighCutのすべてのピクセルよりも大きい場合、このときの階調値をBMaxとしてカウントします。
3番目のステップは、計算したMinBlue / MaxBlueに従ってマッピングテーブルを作成することです。マッピングテーブルのルールは、MinBlueより小さい値の場合、暗黙は0です(実際、この文は正しくありません。これは、自動色補正オプションダイアログボックスで影によって設定された色に関連しています。デフォルトでは、黒であり、対応するRGBコンポーネントはすべて0であるため、ここでは0を意味します。必要に応じて、他の色を指定することもできますパラメータ)、MaxBlueより大きい値の場合、インプリシットは255です(同様に、この値はハイライトのカラー設定に関連しています)。MinBlueとMaxBlueの間の値の場合、線形インプリシットが実行され、デフォルトはインプリシットです。それは0から255の間です(もちろん、実際にはダークトーンとハイライトの設定に関連しており、ここでは実際には線形暗黙ではありません。ガンマ補正があり、簡単にするために、線形置換効果に大きな問題はありません)。
最後のステップは、各チャネルの画像データを推測することです。
// AutoLevel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<iostream>
#include<vector>
#include <algorithm>
using namespace cv;
void AutoLevelsAdjust(cv::Mat& src, cv::Mat& dst)
{
CV_Assert(!src.empty() && src.channels() == 3);
//统计灰度直方图
int BHist[256] = {
0 }; //B分离
int GHist[256] = {
0 }; //G分量
int RHist[256] = {
0 }; //R分量
cv::MatIterator_<Vec3b> its, ends;
for (its = src.begin<Vec3b>(), ends = src.end<Vec3b>(); its != ends; its++)
{
BHist[(*its)[0]]++;
GHist[(*its)[1]]++;
RHist[(*its)[2]]++;
}
//设置LowCut和HighCut
float LowCut = 0.5;
float HighCut = 0.5;
//根据LowCut和HighCut查找每个通道最大值最小值
int BMax = 0, BMin = 0;
int GMax = 0, GMin = 0;
int RMax = 0, RMin = 0;
int TotalPixels = src.cols * src.rows;
float LowTh = LowCut * 0.01 * TotalPixels;
float HighTh = HighCut * 0.01 * TotalPixels;
//B通道查找最小最大值
int sumTempB = 0;
for (int i = 0; i < 256; i++)
{
sumTempB += BHist[i];
if (sumTempB >= LowTh)
{
BMin = i;
break;
}
}
sumTempB = 0;
for (int i = 255; i >= 0; i--)
{
sumTempB += BHist[i];
if (sumTempB >= HighTh)
{
BMax = i;
break;
}
}
//G通道查找最小最大值
int sumTempG = 0;
for (int i = 0; i < 256; i++)
{
sumTempG += GHist[i];
if (sumTempG >= LowTh)
{
GMin = i;
break;
}
}
sumTempG = 0;
for (int i = 255; i >= 0; i--)
{
sumTempG += GHist[i];
if (sumTempG >= HighTh)
{
GMax = i;
break;
}
}
//R通道查找最小最大值
int sumTempR = 0;
for (int i = 0; i < 256; i++)
{
sumTempR += RHist[i];
if (sumTempR >= LowTh)
{
RMin = i;
break;
}
}
sumTempR = 0;
for (int i = 255; i >= 0; i--)
{
sumTempR += RHist[i];
if (sumTempR >= HighTh)
{
RMax = i;
break;
}
}
//对每个通道建立分段线性查找表
//B分量查找表
int BTable[256] = {
0 };
for (int i = 0; i < 256; i++)
{
if (i <= BMin)
BTable[i] = 0;
else if (i > BMin && i < BMax)
BTable[i] = cvRound((float)(i - BMin) / (BMax - BMin) * 255);
else
BTable[i] = 255;
}
//G分量查找表
int GTable[256] = {
0 };
for (int i = 0; i < 256; i++)
{
if (i <= GMin)
GTable[i] = 0;
else if (i > GMin && i < GMax)
GTable[i] = cvRound((float)(i - GMin) / (GMax - GMin) * 255);
else
GTable[i] = 255;
}
//R分量查找表
int RTable[256] = {
0 };
for (int i = 0; i < 256; i++)
{
if (i <= RMin)
RTable[i] = 0;
else if (i > RMin && i < RMax)
RTable[i] = cvRound((float)(i - RMin) / (RMax - RMin) * 255);
else
RTable[i] = 255;
}
//对每个通道用相应的查找表进行分段线性拉伸
cv::Mat dst_ = src.clone();
cv::MatIterator_<Vec3b> itd, endd;
for (itd = dst_.begin<Vec3b>(), endd = dst_.end<Vec3b>(); itd != endd; itd++)
{
(*itd)[0] = BTable[(*itd)[0]];
(*itd)[1] = GTable[(*itd)[1]];
(*itd)[2] = RTable[(*itd)[2]];
}
dst = dst_;
}
int main()
{
Mat image = imread("E:\\picture\\wutian.jpg");
Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC1);
AutoLevelsAdjust(image, dst);
imshow("src", image);
imshow("dst", dst);
while (char(waitKey(1)) != 'q') {
}
}
自動カラーグラデーションは、最も安定している曇り除去に使用されます。ダークチャネル曇り除去、コントラスト曇り除去の最適化、カラーラインベースの曇り除去など、他の多くの拡張方法がありますが、これらのアルゴリズムはまだ非常に安定していません。事前知識が無効である場合、処理の歪みはより深刻になります。ただし、自動カラースケールは比較的安定しています。