[w5d5] Histogram Stretch, Filtering
(Ubuntu 18.04.6 LTS)
2022.03.18.
C++、VSコードを使用
プログラマー自主走行Defcos 3期
従来の対照は,特定の値を基準として分布する形で与えられた.その値の多くは、平均値または輝度の中間値128である.
適用される式は次のとおりです.
ポイントを追加すると、その位置をポイントとして取得できます.
cv::normalizeを使用してヒストグラムストレッチを実行することもできます.
一番左は既存の写真で、2番目は普通のヒストグラムで、3番目は1%のヒストグラムで、よりはっきりした画像が見えます.
ヒストグラム等化は、区間全体にわたって均一な分布の形で現れる技術であり、ヒストグラムを求め、正規化した後に累積分布関数を求め、最大値に四捨五入を乗じる.以下のウィキサイトの内容を確認し、記入しました.
https://en.wikipedia.org/wiki/Histogram_equalization
画像のコントラスト値をテキストファイルに挿入します.その後Pythonを利用して個数を求めます.
フィルタリングは、必要な情報のみを用いる方法であり、空間フィルタリングを処理する画像処理において、mask、kernelと呼ばれるマトリクスを用いてぼかし、エッジ検出などのフィルタリングを行う.OpenCVでは、cv::filter 2 D関数を使用できます.
https://docs.opencv.org/3.4/d4/d86/group__imgproc__filter.html#filter_depths
kernelはフィルタリング用のマトリクスです.
アンカーはアンカー位置であり、ポイント(-1,-1)の場合はフィルタの中心をアンカーとして使用します.
deltaは追加する値で、borderTypeはエッジの処理方法を決定します.borderタイプに関する情報は、以下でさらに参照できます.
https://docs.opencv.org/3.4/d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5a697c1b011884a7c2bdc0e5caf7955661
https://en.wikipedia.org/wiki/Image_embossing
コード実行結果は以下の通りです.
2022.03.18.
C++、VSコードを使用
プログラマー自主走行Defcos 3期
histogram stretch
従来の対照は,特定の値を基準として分布する形で与えられた.その値の多くは、平均値または輝度の中間値128である.
dst = src + (src - m) * alpha
dst = src + (128 - m)
ヒストグラムストレッチのヒストグラム上の分布は、最大値と最小値を用いて輝度を調節する.適用される式は次のとおりです.
dst = 255/(G_max - G_min) * (src - G_min)
OpenCVで最大最小値を求める関数はcv::minmaxLocである.void cv::minMaxLoc ( InputArray src,
double * minVal,
double * maxVal = 0,
Point * minLoc = 0,
Point * maxLoc = 0,
InputArray mask = noArray()
)
minVal、maxValでは、各値を含む2変数のアドレスを入力するだけです.ポイントを追加すると、その位置をポイントとして取得できます.
cv::normalizeを使用してヒストグラムストレッチを実行することもできます.
void cv::normalize ( InputArray src,
InputOutputArray dst,
double alpha = 1,
double beta = 0,
int norm_type = NORM_L2,
int dtype = -1,
InputArray mask = noArray()
)
norm typeをNORM MINMAXに設定すると、alphaを最小値、betaを最大値として使用できます.// 예시 코드
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat src = cv::imread("./resources/lenna.bmp",cv::IMREAD_COLOR);
if (src.empty()){
std::cerr << "Image load failed!" << std::endl;
return -1;
}
double gmin,gmax;
cv::minMaxLoc(src,&gmin,&gmax);
cv::Mat dst = (src-gmin)*255/(gmax-gmin);
cv::Mat dst2,src2;
cv::cvtColor(src,src2,cv::COLOR_BGR2GRAY);
cv::normalize(src2,dst2,0,255,cv::NORM_MINMAX);
cv::imshow("image",src);
cv::imshow("dst",dst);
cv::imshow("image2",src2);
cv::imshow("dst2",dst2);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
しかし、最大値、最小値周辺の画素数が少ない場合やノイズが発生する場合、単純な最大最小値は実現しにくい.一定の割合を超えると、その値に基づいてヒストグラムstretchを実行できます.コードは以下の通りです.#include "opencv2/opencv.hpp"
#include <iostream>
void histogram_stretching(const cv::Mat& src, cv::Mat& dst);
void histogram_stretching_mod(const cv::Mat& src, cv::Mat& dst);
int main()
{
cv::Mat src = cv::imread("./resources/lenna.bmp", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "Image load failed!" << std::endl;
return -1;
}
cv::Mat dst1, dst2;
histogram_stretching(src, dst1);
histogram_stretching_mod(src, dst2);
cv::imshow("src", src);
cv::imshow("dst1", dst1);
cv::imshow("dst2", dst2);
cv::waitKey();
}
void histogram_stretching(const cv::Mat& src, cv::Mat& dst)
{
double gmin, gmax;
cv::minMaxLoc(src, &gmin, &gmax);
dst = (src - gmin) * 255 / (gmax - gmin);
}
void histogram_stretching_mod(const cv::Mat& src, cv::Mat& dst)
{
int hist[256] = {0,};
for(int y=0;y<src.rows;y++){
for(int x=0;x<src.cols;x++){
hist[src.at<uchar>(cv::Point(y,x))]+=1;
}
}
int gmin, gmax;
int ratio = int(src.cols * src.rows * 0.01);
for (int i = 0, s = 0; i < 255; i++) {
s += hist[i];
if (s>=ratio){
gmin = i;
break;
}
}
for (int i = 255, s = 0; i >= 0; i--) {
s += hist[i];
if (s>=ratio){
gmax = i;
break;
}
}
dst = (src-gmin)/(gmax-gmin)*255;
}
一番左は既存の写真で、2番目は普通のヒストグラムで、3番目は1%のヒストグラムで、よりはっきりした画像が見えます.
histogram equalization
ヒストグラム等化は、区間全体にわたって均一な分布の形で現れる技術であり、ヒストグラムを求め、正規化した後に累積分布関数を求め、最大値に四捨五入を乗じる.以下のウィキサイトの内容を確認し、記入しました.
https://en.wikipedia.org/wiki/Histogram_equalization
画像のコントラスト値をテキストファイルに挿入します.その後Pythonを利用して個数を求めます.
# python 3
f = open("counti.txt",'r')
hist = [0]*256
while True:
line = f.readline()
if not line: break
hist[int(line)]+=1
hist_sum = float(sum(hist))
cdf = 0
for idx, count in enumerate(hist):
if (count!=0):
norm_hist=count/hist_sum
cdf += norm_hist
dist_val = int(round(cdf*255,0))
print(f'{idx:3}: count: {count}, norm_hist = {norm_hist:.3f}, cdf = {cdf:.3f}, dst_val = {dist_val}')
f.close
結果値は以下のとおりです.countは個数であり,norm histは総数で割った値であり,cdfは累積分布関数である.255の範囲内で滑らかにするために、cdfを255に乗じて四捨五入する. 52: count: 1, norm_hist = 0.016, cdf = 0.016, dst_val = 4
55: count: 3, norm_hist = 0.047, cdf = 0.062, dst_val = 16
58: count: 2, norm_hist = 0.031, cdf = 0.094, dst_val = 24
59: count: 3, norm_hist = 0.047, cdf = 0.141, dst_val = 36
60: count: 1, norm_hist = 0.016, cdf = 0.156, dst_val = 40
61: count: 4, norm_hist = 0.062, cdf = 0.219, dst_val = 56
62: count: 1, norm_hist = 0.016, cdf = 0.234, dst_val = 60
63: count: 2, norm_hist = 0.031, cdf = 0.266, dst_val = 68
64: count: 2, norm_hist = 0.031, cdf = 0.297, dst_val = 76
65: count: 3, norm_hist = 0.047, cdf = 0.344, dst_val = 88
66: count: 2, norm_hist = 0.031, cdf = 0.375, dst_val = 96
67: count: 1, norm_hist = 0.016, cdf = 0.391, dst_val = 100
68: count: 5, norm_hist = 0.078, cdf = 0.469, dst_val = 120
69: count: 3, norm_hist = 0.047, cdf = 0.516, dst_val = 131
70: count: 4, norm_hist = 0.062, cdf = 0.578, dst_val = 147
71: count: 2, norm_hist = 0.031, cdf = 0.609, dst_val = 155
72: count: 1, norm_hist = 0.016, cdf = 0.625, dst_val = 159
73: count: 2, norm_hist = 0.031, cdf = 0.656, dst_val = 167
75: count: 1, norm_hist = 0.016, cdf = 0.672, dst_val = 171
76: count: 1, norm_hist = 0.016, cdf = 0.688, dst_val = 175
77: count: 1, norm_hist = 0.016, cdf = 0.703, dst_val = 179
78: count: 1, norm_hist = 0.016, cdf = 0.719, dst_val = 183
79: count: 2, norm_hist = 0.031, cdf = 0.750, dst_val = 191
83: count: 1, norm_hist = 0.016, cdf = 0.766, dst_val = 195
85: count: 2, norm_hist = 0.031, cdf = 0.797, dst_val = 203
87: count: 1, norm_hist = 0.016, cdf = 0.812, dst_val = 207
88: count: 1, norm_hist = 0.016, cdf = 0.828, dst_val = 211
90: count: 1, norm_hist = 0.016, cdf = 0.844, dst_val = 215
94: count: 1, norm_hist = 0.016, cdf = 0.859, dst_val = 219
104: count: 2, norm_hist = 0.031, cdf = 0.891, dst_val = 227
106: count: 1, norm_hist = 0.016, cdf = 0.906, dst_val = 231
109: count: 1, norm_hist = 0.016, cdf = 0.922, dst_val = 235
113: count: 1, norm_hist = 0.016, cdf = 0.938, dst_val = 239
122: count: 1, norm_hist = 0.016, cdf = 0.953, dst_val = 243
126: count: 1, norm_hist = 0.016, cdf = 0.969, dst_val = 247
144: count: 1, norm_hist = 0.016, cdf = 0.984, dst_val = 251
154: count: 1, norm_hist = 0.016, cdf = 1.000, dst_val = 255
各値に基づいてテーブルが作成されたと解釈することができ、例えば、元の144値は、平滑化後に251を付与することができる.変更すると輝度値が均等に分布します.filtering
フィルタリングは、必要な情報のみを用いる方法であり、空間フィルタリングを処理する画像処理において、mask、kernelと呼ばれるマトリクスを用いてぼかし、エッジ検出などのフィルタリングを行う.OpenCVでは、cv::filter 2 D関数を使用できます.
void cv::filter2D ( InputArray src,
OutputArray dst,
int ddepth,
InputArray kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT
)
ddepthはデータの深さを表し、-1は処理がソースと同じであることを示す.種類は下記のリンクでご覧いただけます.https://docs.opencv.org/3.4/d4/d86/group__imgproc__filter.html#filter_depths
kernelはフィルタリング用のマトリクスです.
アンカーはアンカー位置であり、ポイント(-1,-1)の場合はフィルタの中心をアンカーとして使用します.
deltaは追加する値で、borderTypeはエッジの処理方法を決定します.borderタイプに関する情報は、以下でさらに参照できます.
https://docs.opencv.org/3.4/d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5a697c1b011884a7c2bdc0e5caf7955661
// 예제 코드: 엠보싱.
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat src = cv::imread("./resources/lenna.bmp",cv::IMREAD_GRAYSCALE);
float data[] = {-1,-1,0,-1,0,1,1,1,1};
cv::Mat kernel(3,3,CV_32FC1,data);
cv::Mat dst;
if (src.empty()){
std::cerr << "Image load failed!" << std::endl;
return -1;
}
cv::filter2D(src,dst,-1,kernel);
cv::imshow("image",src);
cv::imshow("dst",dst);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
サンプルコードは、エンボスを実装するために作成されたフィルタマスクであり、エンボスに関する情報は次のリンクで参照できます.https://en.wikipedia.org/wiki/Image_embossing
コード実行結果は以下の通りです.
Reference
この問題について([w5d5] Histogram Stretch, Filtering), 我々は、より多くの情報をここで見つけました https://velog.io/@anecjong/w5d5テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol