利用查找表对目标图像生成反向图像
对于灰度图,查找表是256行1列的向量,每个值对应转换后的像素值。
下面的函数建立反向查找表,对原图进行重映射得到反向图像。
cv::Mat reversePixel(const cv::Mat& image)
{
cv::Mat lut(256, 1, CV_8UC1);
cv::Mat result;
for (int i = 0; i < 256; i++)
{
lut.at<uchar>(i) = 255 - i;
}
cv::LUT(image, lut, result);
return result;
}
利用直方图伸展查找表提高图像对比度
对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,对比度越高,图像的表现就越直观。
本例在4.2 Histogram1D
类的基础上,新写了成员函数用来提高图像对比度。具体的算法是:利用图像直方图和要规整的像素百分比找到imin和imax,再创建对应查找表,最后根据查找表对原图重新映射。
class Histogram1D
{
private:
int histSize[1]; //立方图中箱子的数量
float hranges[2]; //值范围
const float* ranges[1]; //值范围的指针,用于指向值范围
int channels[1]; //要检查的通道数量
public:
//默认初始化用于灰度图
Histogram1D();
//用于彩色图初始化
Histogram1D(int channel);
//生成直方图hist
cv::Mat getHistogram(const cv::Mat& image);
//生成直方图图像
cv::Mat getHistogramImage(const cv::Mat& image, int zoom = 1);
//提高对比度函数,百分比表示伸展后图像的 最小强度值0 和 最大强度值255 像素的百分比
void improveContrast(const cv::Mat& image, cv::Mat& result, float percentile)
{
//计算直方图
cv::Mat hist = getHistogram(image);
//计算伸展后0和255分别的像素个数
float number = image.total() * percentile;
//从前统计箱子中的像素个数总和,直到超过number,记下箱子序号
int imin = 0;
for (float count = 0.0; imin < 256; imin++)
{
if ((count += hist.at<float>(imin)) >= number)
{
break;
}
}
int imax = 255;
//从后统计箱子中的像素个数总和,直到超过number,记下箱子序号
for (float count = 0.0; imax >= 0; imax--)
{
if ((count += hist.at<float>(imax)) >= number)
{
break;
}
}
//创建对应查找表
cv::Mat lut(256, 1, CV_8UC1);
//重新映射强度值,小于imin的像素归为0,大于imax的像素归为255,两者之间的像素进行线性映射
for (int i = 0; i < 256; i++)
{
if (i <= imin)
{
lut.at<uchar>(i) = 0;
}
else if (i >= imax)
{
lut.at<uchar>(i) = 255;
}
else
{
lut.at<uchar>(i) = 255 * (i - imin) / (imax - imin);
}
}
//应用查找表
cv::LUT(image, lut, result);
}
};
总结:查找和直方图都是256*1的矩阵,查找表描述每个像素值变换后的值,直方图描述当前图每个像素数量。
效果
可以看到,图像的一些细节被加强了。
可以看出,前面和后面的部分像素均被规整到255,曲线中间部分被拉长了。
有白线的原因是因为查找表的计算应用的是整数运算,有些像素值计算不到。
利用查找表构建减色函数
第二章是通过循环遍历对每个像素应用减色函数,更高效的做法是先计算好所有的减色值,然后用查找表修改每个像素。
在多通道图像上应用一维查找表时,同一个查找表会独立应用在所有通道上,如果查找表超过一个维度,和原图的通道数必须相同。
void colorReduce(cv::Mat& image, int div = 64)
{
cv::Mat lookup(256, 1, CV_8U);
for (int i = 0; i < 256; i++)
{
lookup.at<uchar>(i) = i / div * div + div / 2;
}
cv::LUT(image, lookup, image);
}
效果