記事のディレクトリ
プロジェクトでは、ドキュメントイメージを強化する必要があるため、つまり、あいまいな、暗い、または不均一なドキュメントを処理して、その後の識別を容易にする必要があるためです。画像強調方法は、主に空間領域と周波数領域の2つの側面に分けられます。空間しきい値強調方法、色強調(ヒストグラム均等化、コントラストおよびガマ強調など)、ぼかし(平均フィルタリングなど)、シャープ化(コントラスト強調を実現するための局所標準偏差)。ウェーブレット変換などの周波数領域法は、画像の特定の変換領域内の画像の変換係数を操作し、逆変換によって画像強調効果を取得します。一般的に、実際のプロジェクトでは、これらの方法の1つ以上が画像の強調に使用される可能性があり、効果は一般に非常に貧弱です。これらのアルゴリズムを融合して、必要な効果を実現する必要があります。
1.分割モードに基づく画像強調
異なる照明の下で同じシーンの写真をそれぞれ撮影している画像AとBがあるとします。ここで、Aは原色を表し、Bは混合色を表します。次に、このシーンの配光をモデル化して、分割モードの計算式を取得します。結果の色=(原色/混合色)* 255。
- 具体的にはどういう意味ですか?
各チャネルの値を分析し、基本色に基づいて強調します。基本色の値が混合色以上の場合、結果の色は白になります。基本色が混合色よりも小さい場合、結果は白になります。ベースカラーよりも暗くなります。
- このアルゴリズムがドキュメント画像の強調に適しているのはなぜですか?
ドキュメントの画像は通常、テキストと背景で構成されています。テキストは黒で、背景は白です。コントラストなどを単純に強調すると、明るい画像や暗い画像には確かに効果的ですが、ドキュメントの場合、この方法では、強調効果を実現するのではなく、テキストの一部が欠落します。分割モードによる画像強調はこれを考慮しており、フォントなどの暗いものは暗くなり、背景などの明るいものは明るくなります。
- それを達成する方法は?
問題の仕様は、異なる照明で同じシーンの写真を撮る画像AとBであり、次のようになります。
照明分布L = A / B
AとLがわかっている場合、B = A / L(BはAの非照明の結果です)
ここで、Aは強調する必要のある画像を表し、Bはガウスフィルタリング後の画像を表します。次に、A / Bを実行すると、強調された画像が得られます。簡単ではありませんか。
2. c ++ OpenCVに基づく実装
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat image = imread("./pic/raw.png");
//划分算法
//如果混合色与基色相同则结果色为白色
//如混合色为白色则结果色为基色不变
//如混合色为黑色则结果色为白色
Mat src = image.clone();
src.convertTo(src, CV_32FC3, 1.0 / 255);
Mat gauss;
Mat dst = src.clone();
GaussianBlur(src, gauss, Size(101, 101), 0);
dst = src / gauss;
dst.convertTo(dst, CV_8UC3, 255);
imshow("dst", dst);
waitKey();
return 0;
}
結果の表示:
3.補助拡張アルゴリズム
1行目や3行目など、一部の画像が適切に処理されていないことがわかります。処理結果には多くのブラックノイズがあるため、他の拡張アルゴリズムを使用してフォローアップを支援できます。ここでは、ガンマコントラスト強調アルゴリズムを選択します。具体的な実装は次のとおりです。
//Gamma校正 fGamaa=0.45是常用值
void GammaCorrection(Mat& src, Mat& dst, float fGamma)
{
CV_Assert(src.data);
// accept only char type matrices
CV_Assert(src.depth() != sizeof(uchar));
// build look up table
unsigned char lut[256];
for (int i = 0; i < 256; i++)
{
lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
}
dst = src.clone();
const int channels = dst.channels();
switch (channels)
{
case 1:
{
MatIterator_<uchar> it, end;
for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)
*it = lut[(*it)];
break;
}
case 3:
{
MatIterator_<Vec3b> it, end;
for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++)
{
(*it)[0] = lut[((*it)[0])];
(*it)[1] = lut[((*it)[1])];
(*it)[2] = lut[((*it)[2])];
}
break;
}
}
}
完全なコードは次のとおりです。
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//Gamma校正 fGamaa=0.45是常用值
void GammaCorrection(Mat& src, Mat& dst, float fGamma)
{
CV_Assert(src.data);
// accept only char type matrices
CV_Assert(src.depth() != sizeof(uchar));
// build look up table
unsigned char lut[256];
for (int i = 0; i < 256; i++)
{
lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
}
dst = src.clone();
const int channels = dst.channels();
switch (channels)
{
case 1:
{
MatIterator_<uchar> it, end;
for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)
*it = lut[(*it)];
break;
}
case 3:
{
MatIterator_<Vec3b> it, end;
for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++)
{
(*it)[0] = lut[((*it)[0])];
(*it)[1] = lut[((*it)[1])];
(*it)[2] = lut[((*it)[2])];
}
break;
}
}
}
int main(int argc, char** argv)
{
Mat image = imread("./pic/raw.jpg");
划分算法
//如果混合色与基色相同则结果色为白色
//如混合色为白色则结果色为基色不变
//如混合色为黑色则结果色为白色
Mat src = image.clone();
src.convertTo(src, CV_32FC3, 1.0 / 255);
Mat gauss;
Mat dst = src.clone();
GaussianBlur(src, gauss, Size(101, 101), 0);
dst = src / gauss;
dst.convertTo(dst, CV_8UC3, 255);
gamma变换
Mat matGamma;
GammaCorrection(dst.clone(), matGamma,1.5);
//显示最终结果
//namedWindow("Soure", 0);
namedWindow("dst", 0);
imshow("Soure", image);
imshow("dst", matGamma);
waitKey();
return 0;
}
参照接続: