画像拡張:適応拡張アルゴリズム(Android-OpenCV)
適応増強アルゴリズムの具体的な原理は、カラー画像の適応コントラスト増強を参照することができる.
実際、多くのブログではこれを説明していますが、完全なコードを公開したくないので、私が実現したコードを貼っています.
まずアルゴリズムについて説明するが,式に直接従うと,アルゴリズムの複雑さはn^2*N^2であり,nはウィンドウサイズ,Nは画像サイズであるが,M(x,y)=M(x,y−1)+{SUM[f(xr)]−SUM[f(xl)]ここで、SUM[f(xr)]は右側が再計算する列を表し、SUM[f(xl)]は削除する必要がある左の列であり、アルゴリズムの複雑さはn*N^2に減少する.
同様にSigmaの計算についても同様の結果が得られ,具体的な導出過程は言わず,直接結果:S(x,y)=S(x,y−1)+{SUM[f(xr)^2]−SUM[f(xl)^2]}/n+M(x,y−1)^2−M(x,y)^2補足:各ウィンドウ列の値を事前に計算することにより,アルゴリズムの乱れはN^2に最適化され,ウィンドウサイズとはあまり関係なく,画像サイズのみに関連し,1024*968の画像は1秒以内で、もちろんマルチスレッド処理を追加すれば、速度が速くなります.
コードリファレンスは次のとおりです.(小さなエラーがある場合があります)
その他の非アルゴリズム部分コードについては、以下を参照してください.https://github.com/dingpwen/ImageProcess
初心者にとって最も犯すべき過ちはimgである.at(i,j),ここでucharはfloatと書くことはできないに違いない.
実際、多くのブログではこれを説明していますが、完全なコードを公開したくないので、私が実現したコードを貼っています.
まずアルゴリズムについて説明するが,式に直接従うと,アルゴリズムの複雑さはn^2*N^2であり,nはウィンドウサイズ,Nは画像サイズであるが,M(x,y)=M(x,y−1)+{SUM[f(xr)]−SUM[f(xl)]ここで、SUM[f(xr)]は右側が再計算する列を表し、SUM[f(xl)]は削除する必要がある左の列であり、アルゴリズムの複雑さはn*N^2に減少する.
同様にSigmaの計算についても同様の結果が得られ,具体的な導出過程は言わず,直接結果:S(x,y)=S(x,y−1)+{SUM[f(xr)^2]−SUM[f(xl)^2]}/n+M(x,y−1)^2−M(x,y)^2補足:各ウィンドウ列の値を事前に計算することにより,アルゴリズムの乱れはN^2に最適化され,ウィンドウサイズとはあまり関係なく,画像サイズのみに関連し,1024*968の画像は1秒以内で、もちろんマルチスレッド処理を追加すれば、速度が速くなります.
コードリファレンスは次のとおりです.(小さなエラーがある場合があります)
private:
// delta^2 = delta0^2 + [sumRight(f^2) - sumLeft(f^2)]/N + M0^2 - M^2
void getMeanFromPreviousCol(const Mat &img, Mat &mean, Mat &sigma, const Mat &sumM, const Mat &sumS, int m, int n, int pI, int pJ) {
int total = (2*m + 1) * (2*n + 1);
/*float M = 0;
for(int i = pI - m; i <= pI + m; ++i) {
M += (img.at(i, pJ + n) - img.at(i, pJ -n -1));
}*/
float M = sumM.at<float>(pI, pJ + n) - sumM.at<float>(pI, pJ -n -1);
M /= total;
mean.at<float>(pI, pJ) = M + mean.at<float>(pI, pJ -1);
/*float S = 0;
for(int i = pI - m; i <= pI + m; ++i) {
S += (pow(img.at(i, pJ + n), 2) - pow(img.at(i, pJ -n -1), 2));
}*/
float S = sumS.at<float>(pI, pJ + n) - sumS.at<float>(pI, pJ -n -1);
S /= total;
S += pow(mean.at<float>(pI, pJ -1), 2) - pow(mean.at<float>(pI, pJ), 2);
sigma.at<float>(pI, pJ) = S + sigma.at<float>(pI, pJ -1);
}
void getMeanFromPreviousRow(const Mat &img, Mat &mean, Mat &sigma, const vector<float> &sumM, const vector<float> &sumS,
int m, int n, int pI, int pJ) {
if(pJ != n) {
LOGE("line0-something is wrong!with pos=(%d, %d)", pI, pJ);
return;
}
int total = (2*m + 1) * (2*n + 1);
/*float M = 0;
for(int j = pJ - n; j <= pJ + n; ++j) {
M += (img.at(pI + n, j) - img.at(pI - n -1, j));
}*/
float M = sumM[pI + n] - sumM[pI - n -1];
M /= total;
mean.at<float>(pI, pJ) = M + mean.at<float>(pI - 1, pJ);
/*float S = 0;
for(int j = pJ - n; j <= pJ + n; ++j) {
S += (pow(img.at(pI + n, j), 2) - pow(img.at(pI - n -1, j), 2));
}
S /= total;*/
float S = (sumS[pI + n] - sumS[pI - n -1])/total;
S += pow(mean.at<float>(pI - 1, pJ), 2) - pow(mean.at<float>(pI, pJ), 2);
sigma.at<float>(pI, pJ) = S + sigma.at<float>(pI - 1, pJ);
}
//Count col sum
void preCountColSum(const Mat &img, Mat &sumM, Mat &sumS, int m) {
int colSize = (m << 1) + 1;
for(int j=0; j<img.cols; ++j) {
float tM = 0;
float tS = 0;
for(int i=0; i<colSize; ++i) {
tM += img.at<uchar>(i, j);
tS += (float)pow(img.at<uchar>(i, j), 2);
}
sumM.at<float>(m, j) = tM;
sumS.at<float>(m, j) = tS;
for(int i=m+1; i<img.rows - m; ++i) {
sumM.at<float>(i, j) = sumM.at<float>(i-1, j) + img.at<uchar>(i + m, j) - img.at<uchar>(i - m - 1, j);
sumS.at<float>(i, j) = sumS.at<float>(i-1, j) + (float)pow(img.at<uchar>(i + m, j), 2) - (float)pow(img.at<uchar>(i - m - 1, j), 2);
}
}
}
void preCountRowSum(const Mat &img, vector<float> &sumM, vector<float> &sumS, int n) {
int rowSize = (n << 1) + 1;
for(int i=0; i<img.rows; ++i) {
sumM[i] = 0;
sumS[i] = 0;
for(int j=0; j<rowSize; ++j) {
sumM[i] += img.at<uchar>(i, j);
sumS[i] += (float)pow(img.at<uchar>(i, j), 2);
}
}
}
void getMean(const Mat &img, Mat &mean, Mat &sigma, const Mat &sumM, const Mat &sumS, vector<float> &rowSumM, vector<float> &rowSumS,
int m, int n, int pI, int pJ) {
if(pI - m < 0 || pI + m >= img.rows || pJ - n < 0 || pJ + n >= img.cols) {
mean.at<float>(pI, pJ) = -1;
sigma.at<float>(pI, pJ) = 0;
return ;
}
if(pJ == n && pI > m) {
return getMeanFromPreviousRow(img, mean, sigma, rowSumM, rowSumS, m, n, pI, pJ);
} else if(pJ > n) {
return getMeanFromPreviousCol(img, mean, sigma, sumM, sumS, m, n, pI, pJ);
}
float M = 0;
int total = (2*m + 1) * (2*n + 1);
for(int i=pI -m; i<= pI + m; ++i) {
for(int j=pJ - n; j <= pJ + n; ++j) {
M += img.at<uchar>(i, j);
}
}
M /= total;
mean.at<float>(pI, pJ) = M;
float S = 0;
float diff;
for(int i=pI -m; i<= pI + m; ++i) {
for(int j=pJ - n; j <= pJ + n; ++j) {
diff = img.at<uchar>(i, j) - M;
S += (diff * diff);
}
}
S /= total;
sigma.at<float>(pI, pJ) = S;
}
void getMean(const Mat &img, Mat &mean, Mat &sigma, int m, int n){
Mat colSumM = Mat::zeros(img.rows, img.cols, CV_32FC1);
Mat colSumS = Mat::zeros(img.rows, img.cols, CV_32FC1);
preCountColSum(img, colSumM, colSumS, m);
vector<float> rowSumM;
vector<float> rowSumS;
rowSumM.reserve((unsigned)img.rows);
rowSumS.reserve((unsigned)img.rows);
preCountRowSum(img, rowSumM, rowSumS, n);
for(int i=0;i<mImg.rows; ++i) {
//LOGI("line0-row:%d", i);
for (int j = 0; j < mImg.cols; ++j) {
getMean(img, mean, sigma, colSumM, colSumS, rowSumM, rowSumS, m, n, i, j);
}
}
float value;
for(int i=0;i<mImg.rows; ++i) {
for (int j = 0; j < mImg.cols; ++j) {
value = sigma.at<float>(i, j);
sigma.at<float>(i, j) = sqrt(value);
}
}
}
その他の非アルゴリズム部分コードについては、以下を参照してください.https://github.com/dingpwen/ImageProcess
初心者にとって最も犯すべき過ちはimgである.at(i,j),ここでucharはfloatと書くことはできないに違いない.