【Emgu.CV教程】第24篇 、色彩处理之LUT()查找表转换颜色

发布时间:2024年01月05日

? ? ? ? LUT (Look-Up Table)查找表转换,是对原始图像的像素数值进行快速转换,以实现图像的像素压缩目的。LUT()函数的官方定义如下:

public static void LUT(
    IInputArray src,  // 输入图像
    IInputArray lut, // 查找表
    IOutputArray dst, // 输出图像
)

? ? ? ? 根据网上的各位大神,结合我的理解,LUT()实现像素压缩的原理是:以颜色深度为Cv8U的单通道灰度图来说,图像中像素数值只能在[0,255]区间内分布。如果我定义一个256个长度的一维数组LUT[256]原始图像映射到目标图像的方法是:

  • 像素值为0 的点,用LUT[0]代替;
  • 像素值为1 的点,用LUT[1]代替;
  • 像素值为2 的点,用LUT[2]代替;
  • ...
  • 像素值为254 的点,用LUT[254]代替;
  • 像素值为255 的点,用LUT[255]代替;

? ? ? ? LUT[256]数组的值,是由用户自己定义的,如果LUT[0] = 255,LUT[1] = 255 ,其余全是0,你看看,是不是把图像压缩成只有255和0了。其中原始图像的像素值是0和1的,转换成255,剩余全部转换成0,这么说简单吧。

1、图像压缩

? ? ? ? 举个例子,原始图像是这个均匀分布的灰度图:

? ? ? ? 如果我想压缩像素值,让目标图像的值只输出0、35、70、105、140、175、210、245,也就是原始图像在0到34之间,变成0;35到69之间,变成35;70到104之间,变成70;105到139之间变成105;140到174之间变成140;175到209之间变成175;210到244之间变成210;245及以上变成245,代码如下:

Mat tempMat = srcMat.Clone(); // 深拷贝
CvInvoke.CvtColor(tempMat, tempMat, ColorConversion.Bgr2Gray);
Matrix<byte> matrixLUT = new Matrix<byte>(1, 256, 1);
for (int n = 0; n < 256; n++)
{
    matrixLUT.Data[0, n] = (byte)(n / 35 * 35);
}

Mat dstMat = new Mat(tempMat.Rows, tempMat.Cols, DepthType.Cv8U, 1);
CvInvoke.LUT(tempMat, matrixLUT, dstMat);
CvInvoke.Imshow("Gray Mat, " + tempMat.Size.ToString(), tempMat);
CvInvoke.Imshow("LUT process Mat, " + dstMat.Size.ToString(), dstMat);

? ? ? ? 标准的灰度图和LUT()函数压缩后的图像如下所示,效果很明显吧:

2、颜色取反

? ? ? ? 之前的文章也讲过颜色取反,其实LUT()函数也可以,但是不常用,代码如下:

Mat dstMat = srcMat.Clone(); // 深拷贝
Mat tempMat = srcMat.Clone(); // 深拷贝
Matrix<byte> matrixLUT = new Matrix<byte>(1, 256, 1);
for (int n = 0; n < 256; n++)
{
    matrixLUT.Data[0, n] = (byte)(255 - n);
}

dstMat = new Mat(tempMat.Rows, tempMat.Cols, Emgu.CV.CvEnum.DepthType.Cv8U, 3);

// tempMat为原始图像
CvInvoke.LUT(tempMat, matrixLUT, dstMat);
CvInvoke.Imshow("LUT process Mat, " + dstMat.Size.ToString(), dstMat);

? ? ? ? 效果用户自己试一试。注意哈:

  • 查找表必须是Matrix<byte>格式的。
  • 压缩效果就看用户自己定义,颜色取反,就是255减去原始像素值。
  • 目标图像,必须是和原始图像大小、颜色深度、通道数完全相同。

3、彩色图像压缩

? ? ? ? 上面两个例子是对灰度的图操作,查找表参数matrixLUT定义方法如下:

Matrix<byte> matrixLUT = new Matrix<byte>(1, 256, 1);

? ? ? ? 如果是直接操作三通道的彩色图像,查找表参数matrixLUT就需要这样定义了:

Matrix<byte> matrixLUT = new Matrix<byte>(1, 256, 3);

? ? ? ? 假如Blue通道值压缩为0、22、44、66... 220、242,Green通道值压缩为0、50、100、150、200、250,Red通道值压缩为9、129、249,代码如下:

Mat tempMat = srcMat.Clone(); // 深拷贝
Matrix<byte> matrixLUT = new Matrix<byte>(1, 256, 3);
for (int n = 0; n < 256; n++)
{
    matrixLUT.Data[0, n * 3] = (byte)(n / 22 * 22);
    matrixLUT.Data[0, (n * 3) + 1] = (byte)(n / 50 * 50);
    if (n <= 100)
    {
        matrixLUT.Data[0, (n * 3) + 2] = 9;
    }

    if (n > 100 && n <= 200)
    {
        matrixLUT.Data[0, (n * 3) + 2] = 129;
    }

    if (n > 200)
    {
        matrixLUT.Data[0, (n * 3) + 2] = 249;
    }
}

Mat dstMat = new Mat(tempMat.Rows, tempMat.Cols, DepthType.Cv8U, 3);
CvInvoke.LUT(tempMat, matrixLUT, dstMat);
CvInvoke.Imshow("LUT process Mat, " + dstMat.Size.ToString(), dstMat);

? ? ? ? 原始图像和压缩后的图像,对比如下:

? ? ? ? 原本图像是均匀过渡的,LUT压缩后,颜色少了很多,出现了明显的轮廓痕迹。可以在VS2022里看以下目标图像的像素点值,是不是符合咱们定义的规律。

? ? ? ? 经过上面的三个例子,LUT()函数的用法应该很熟悉了吧,但在具体的工程项目中,这个函数到底用处有多大,欢迎大家相互讨论啊。

原创不易,请勿抄袭。共同进步,相互学习。??

文章来源:https://blog.csdn.net/sswss12345/article/details/135339231
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。