# 灰阶变换

image.png

image.png

image.png

``````J = imadjust(I)

``````

``````void imadjust(cv::Mat& input, cv::Mat& output, double low_in = 0.0, double high_in  = 1.0, double low_out = 0.0, double high_out = 1.0, double gamma = 1);//matlab,像素区间[0,1]
void imadjust(cv::Mat& input, cv::Mat& output, std::vector<double> in = { 0.0, 1.0 }, double low_out = 0.0, double high_out = 1.0, double gamma = 1);
void imadjust2(cv::Mat& input, cv::Mat& output, int low_in, int high_in, int low_out, int high_out, double gamma = 1);//opencv，像素区间[0,255]
``````

``````I = imread('pout.tif');J = imadjust(I);imshow(I), figure, imshow(J)
imshow(RGB1), figure, imshow(RGB2)
``````

``````J = imadjust(I)

``````

``````J = imadjust(I,[low_in; high_in],[low_out; high_out],gamma)
``````

I为输入的图像，函数的功能就是把输入图像在[low_in; high_in]灰度级中的像素点，映射为[low_out; high_out]区间的灰度级，gamma为一个可选参数，gamma = 1为线性变换，gamma != 1为伽马变换。

image.png
image.png
image.png

gamma.gif
image.png

``````std::vector<uchar> gammaLut(const double gamma, const double c)
{
std::vector<uchar> lut(256);
for (int i = 0; i < 256; ++i)
lut[i] =  static_cast<uchar>(c * std::pow((double)(i / 255.0), gamma) * 255.0);

return lut;
}
``````

``````for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
double result = 0;
if (input.at<uchar>(i, j) <= low_in)//灰度值小于low_in的像素点
{
result = low_out;//结果为low_out
}
else if (low_in < input.at<uchar>(i, j) && input.at<uchar>(i, j) < high_in)//灰度值在[low_in, high_in]
{
result = k * (input.at<uchar>(i, j) - low_in) + high_in;//灰度值线性变换
result = gamma_lut[static_cast<uchar>(result)];//灰度值gamma变换
}
else
{
result = high_out;//灰度值大于high_in的像素点，结果为high_out
}

output.at<uchar>(i, j) = static_cast<uchar>(result) % 255;
}
``````

``````//imadjust函数的实现

#include<opencv2/opencv.hpp>
#include<iostream>
#include<cassert>
#include<vector>

void imadjust(cv::Mat& input, cv::Mat& output, double low_in = 0.0, double high_in  = 1.0, double low_out = 0.0, double high_out = 1.0, double gamma = 1);//matlab,像素区间[0,1]
void imadjust(cv::Mat& input, cv::Mat& output, std::vector<double> in = { 0.0, 1.0 }, double low_out = 0.0, double high_out = 1.0, double gamma = 1);
void imadjust2(cv::Mat& input, cv::Mat& output, int low_in, int high_in, int low_out, int high_out, double gamma = 1);//opencv，像素区间[0,255]
std::vector<uchar> gammaLut(const double gamma, const double c = 1.0);//灰度值的伽马变换结果表lut

bool is0to1(const double var);

int main()
{
if(src_img.empty()) return -1;

cv::Mat dst_img;
imadjust(src_img, dst_img, 0, 1, 0, 1, 2);

cv::imshow("src_img", src_img);

cv::imshow("dst_img", dst_img);
cv::waitKey(0);

return 0;
}//main

void imadjust(cv::Mat& input, cv::Mat& output, double low_in, double high_in, double low_out, double high_out, double gamma)
{
assert(low_in < high_in && is0to1(low_in) && is0to1(high_in) && is0to1(low_out) && is0to1(high_out));

//将matlab中的灰度值区间[0,1]转为opencv灰度值区间[0,255]
high_in *= 255; high_out *= 255; low_in *= 255; low_out *= 255;

imadjust2(input, output, low_in, high_in, low_out, high_out, gamma);
}
void imadjust(cv::Mat& input, cv::Mat& output, std::vector<double> in, double low_out, double high_out, double gamma)
{
assert(2 == in.size());
double low_in = in[0];
double high_in = in[1];
imadjust(input, output, low_in, high_in, low_out, high_out, gamma);
}

void imadjust2(cv::Mat& input, cv::Mat& output, int low_in, int high_in, int low_out, int high_out, double gamma )//opencv，像素区间[0,255]
{
output = input.clone();
int rows = input.rows;//行
int cols = input.cols;//列
double k = (static_cast<double>(high_out) - low_out) / (high_in - low_in);
std::vector<uchar> gamma_lut = gammaLut(gamma);

switch(input.channels())
{

case 1://灰度图

for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
double result = 0;
if (input.at<uchar>(i, j) <= low_in)//灰度值小于low_in的像素点
{
result = low_out;//结果为low_out
}
else if (low_in < input.at<uchar>(i, j) && input.at<uchar>(i, j) < high_in)//灰度值在[low_in, high_in]
{
result = k * (input.at<uchar>(i, j) - low_in) + high_in;//灰度值线性变换
result = gamma_lut[static_cast<uchar>(result)];//灰度值gamma变换
}
else
{
result = high_out;//灰度值大于high_in的像素点，结果为high_out
}

output.at<uchar>(i, j) = static_cast<uchar>(result) % 255;
}
break;

//彩色图片
case 3:
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
for (int k = 0; k < 3; ++k)
{
double result = 0;
if (input.at<cv::Vec3b>(i, j)[k] <= low_in)
result = low_out;
else if (low_in < input.at<cv::Vec3b>(i, j)[k] && input.at<cv::Vec3b>(i, j)[k] < high_in)
{
result = k * (input.at<cv::Vec3b>(i, j)[k] - low_in) + high_in;
result = gamma_lut[static_cast<uchar>(result)];
}
else
{
result = high_out;
}

output.at<cv::Vec3b>(i, j)[k] = static_cast<uchar>(result) % 255;
}
break;

default:
break;
}
}

bool is0to1(const double var)
{
return 0 <= var && var <= 1;
}

std::vector<uchar> gammaLut(const double gamma, const double c)
{
std::vector<uchar> lut(256);
for (int i = 0; i < 256; ++i)
lut[i] =  static_cast<uchar>(c * std::pow((double)(i / 255.0), gamma) * 255.0);

return lut;
}
``````

image.png

# stretchlim

``````lowhigh = stretchlim(I)
lowhigh = stretchlim(I,Tol)
``````

``````std::vector<double> strecthlim(cv::Mat img, double tol_low = 0.01, double tol_high = 0.99);
``````

``````#pragma once
#include<opencv2/opencv.hpp>
#include<vector>
#include<cassert>

std::vector<int> calcGrayLevel(cv::Mat& img);//计算灰度级，即算出从0到255区间的任意一个灰度值i，在图像img中有多少个像素点的灰度值为i
std::vector<double> pdf(std::vector<int> gray_level, cv::Mat& img);//计算概率密度pdf
std::vector<double> cdf(std::vector<double> pdf);//计算概率分布cdf
double findLow(double input_low, std::vector<double> cdf);
double findHihg(double input_high, std::vector<double> cdf);
std::vector<double> strecthlim(cv::Mat img, double tol_low = 0.01, double tol_high = 0.99);
``````

cpp文件

``````//2-2-1
//stretchlim函数

#include"stretchlim.h"
#include<iostream>

int main()
{

if (img.empty()) return -1;

std::vector<double> v = strecthlim(img);
for (auto& i : v)
std::cout << i << std::endl;

system("pause");
return 0;
}

std::vector<int> calcGrayLevel(cv::Mat& img)//计算灰度级，即算出从0到255区间的任意一个灰度值i，在图像img中有多少个像素点的灰度值为i
{
assert(img.channels() == 1);//只计算灰度图像的
std::vector<int> res(256);
int rows = img.rows;//行
int cols = img.cols;//列

for(int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
int val = img.at<uchar>(i, j);
res[val] += 1;
}

return res;
}

std::vector<double> pdf(std::vector<int> gray_level, cv::Mat& img)//计算概率密度
{
assert(gray_level.size() == 256);

int N = img.rows * img.cols;//像素点总数
std::vector<double> res(256);
for (int i = 0; i < 256; ++i)
res[i] =static_cast<double>(gray_level[i]) / N;

return res;
}

std::vector<double> cdf(std::vector<double> pdf)//计算概率分布cdf
{
assert(pdf.size() == 256);

std::vector<double> res(256);
res[0] = pdf[0];
for (int i = 1; i < 256; ++i)
res[i] = pdf[i] + res[i - 1];
return res;
}

double findLow(double input_low, std::vector<double> cdf)
{
assert(cdf.size() == 256);
//找到分布概率大于我们的输入值input_low处最接近的灰度值，并以此作为最佳分割阈值的最小值
for (int i = 0; i < 256; ++i)
if (cdf[i] > input_low)
return cdf[i];

return 0.0;
}
double findHihg(double input_high, std::vector<double> cdf)
{
assert(256 == cdf.size());
//找到分布概率大于或等于我们的输入值input_high处最接近的灰度值，并以此作为最佳分割阈值的最大值
for(int i = 0; i < 256; ++i)
if(cdf[i] >= input_high)
return cdf[i];

return 0.0;
}

std::vector<double> strecthlim(cv::Mat img, double tol_low, double tol_high)
{
std::vector<double> v(2);
if (img.empty()) return v;

//计算灰度值
std::vector<int> gray_level = calcGrayLevel(img);
//计算概率密度pdf
std::vector<double> p = pdf(gray_level, img);
//计算概率分布cdf
std::vector<double> c = cdf(p);
//寻找tol_low, tol_high
tol_low = findLow(tol_low, c);
tol_high = findHihg(tol_high, c);

if (tol_low == tol_high)
v = { 0.0, 1.0 };
else
v = { tol_low, tol_high };

return v;
}
``````