1

I am newbie in openCV and trying to convert the image of 16 bit grayscale image to a color image using color palatte. I have done this operation when I have 8 bit image but now I am fetching the image frame from the thermal camera which give me 16 bit frame and I can't convert that to 8 bit because it decreases the quality of the image which is useless. In 8 bit image I have use LUT function for doing this task.

My Lookup table Code for 8 bit image

    Mat palette, im;
    palette = imread("1.bmp", IMREAD_COLOR);
    im = imread("C:\\Users\\Chandrapal Singh\\Desktop\\New folder\\IMG_0_10_34_45_2018_1.bmp", IMREAD_GRAYSCALE);
    im.convertTo(im, CV_16U);
    cvtColor(im.clone(), im, COLOR_GRAY2BGR);
    double scale = (double)palette.rows / 256;
    uchar b[256], g[256], r[256];
    int i = 0;
    for (double x = 1; x <= palette.rows;) {

        b[i] = palette.at<Vec3b>((int)x, palette.cols / 2)[0];
        g[i] = palette.at<Vec3b>((int)x, palette.cols / 2)[1];
        r[i] = palette.at<Vec3b>((int)x, palette.cols / 2)[2];
        i++;
        x += scale;
    }

    Mat channels[] = { Mat(256,1, CV_8U, b), Mat(256,1, CV_8U, g), Mat(256,1, CV_8U, r) };
    Mat lut;
    cv::merge(channels, 3, lut);

    Mat color;
    cv::LUT(im, lut, color);

In above code palette is a color palatte and im is a grayscale image. I am reading the color of palette and put that in lut and then using LUT function just making a colored image.

So, can anyone help me how I can do the above with 16 bit image. Thanks in Advance.

When I run this code I got execption which says:-

I am getting a exception which says Assertion failed ((lutcn == cn || lutcn == 1) && _lut.total() == 256 && _lut.isContinuous() && (depth == 0 || depth == 1)) in cv:: LUT

  • if 16-bit, is it RGBA where each channel is 4-bit each? – Joseph D. Jun 04 '18 at 07:23
  • As I told sir I am newbie so I don't have much idea about this, Sorry. –  Jun 04 '18 at 07:26
  • I am fetching the image frame from thermal camera, and this is grayscale image and then I convert that to BGR using cvtColor function –  Jun 04 '18 at 07:28
  • just use `CV_16U` in `cvtColor` – Joseph D. Jun 04 '18 at 07:33
  • The problem is in LUT function because the input in the LUT function should be of 8 bit. So, is their any other way through which I can do this? –  Jun 04 '18 at 08:09
  • I have provided the whole code now. So, that my problem is more understandable. Currently I am taking a image and then convert that to 16 bit because I need to convert the 16 bit image frame from the thermal camera. –  Jun 04 '18 at 08:16
  • I answered a question recently which involved applying a LUT - check here https://stackoverflow.com/a/50598388/2836621 – Mark Setchell Jun 04 '18 at 09:15
  • I don't quite understand your question. Do you want to apply a color map, so you can transform a 16 bit grayscale to a 8 bit color image? – jodis Jun 04 '18 at 23:29
  • No, I want to apply custom colorMap to the 16 bit image. –  Jun 05 '18 at 04:35
  • I can't convert 16 bit image to 8 bit because it will reduce the quality of image. –  Jun 05 '18 at 04:38
  • @jodis Sir, Can you give me any idea or Solution for this particular problem –  Jun 05 '18 at 05:35
  • I have once written a function that takes 16 bit grayscale as the input and returns 8 bit color from red to blue. It's based on the HSV color space, and keeps S and V at 1. You loose quite a bit of information like this, depending on your actual value range, but it's good enough for display. I think it could be modified to 16 bit color. (However, I still don't quite get why you want this.) – jodis Jun 05 '18 at 20:56
  • Can you provide me that function. I need that function because the type of the image frame coming from my thermal camera is of 16 bit so I have try to apply color using LUT function but it only supports 8 bit. –  Jun 06 '18 at 04:10
  • I can't help you with the LUT right now, I'm quite a noob myself. If you take a look at the [source](https://github.com/opencv/opencv/blob/7dc88f26f24fa3fd564a282b2438c3ac0263cd2f/modules/core/src/lut.cpp) you see that it is quite simple, in theory. – jodis Jun 07 '18 at 05:33
  • Couldn't resist. I hope my second answer is what you want. – jodis Jun 07 '18 at 06:11

2 Answers2

0

Code to generate a 8 bit color image from 16 bit grayscale. Maps white to red, and black to blue.

#include "opencv2/imgcodecs.hpp"

using namespace cv;
using namespace std;

float a;

Vec3b getBGR(float _val) //unique values only if a >= ~ 0.3 ~= 300 / float(1024);
{   //from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
    float H = a*_val;
    float S = 1;
    float V = 1;

    double      hh, p, q, t, ff;
    long        i;
    Vec3b BGR;

    if (S <= 0.0)
    {       
        BGR[2] = V * 255;//R
        BGR[1] = V * 255;//G
        BGR[0] = V * 255;//B
        return BGR;
    }
    hh = H;
    if (hh >= 360.0) hh = 0.0;// not sure about that
    hh /= 60.0;
    i = (long)hh;
    ff = hh - i;
    p = V * (1.0 - S);
    q = V * (1.0 - (S * ff));
    t = V * (1.0 - (S * (1.0 - ff)));

    switch (i)
    {
    case 0:
        BGR[2] = V * 255;
        BGR[1] = t * 255;
        BGR[0] = p * 255;
        break;
    case 1:
        BGR[2] = q * 255;
        BGR[1] = V * 255;
        BGR[0] = p * 255;
        break;
    case 2:
        BGR[2] = p * 255;
        BGR[1] = V * 255;
        BGR[0] = t * 255;
        break;

    case 3:
        BGR[2] = p * 255;
        BGR[1] = q * 255;
        BGR[0] = V * 255;
        break;
    case 4:
        BGR[2] = t * 255;
        BGR[1] = p * 255;
        BGR[0] = V * 255;
        break;
    case 5:
    default:
        BGR[2] = V * 255;
        BGR[1] = p * 255;
        BGR[0] = q * 255;
        break;
    }

    return BGR;
}

void color_from_gray(Mat& gray, Mat& color)
{   
    double minVal, maxVal;
    minMaxLoc(gray, &minVal, &maxVal);

    //HSV range from 0 (red) to 240 (blue)
    a = 240 / (maxVal - minVal);//global variable!

    MatIterator_<ushort> it, end;
    MatIterator_<Vec3b> iit = color.begin<Vec3b>();//not the most efficient way to iterate
    for (it = gray.begin<ushort>(), end = gray.end<ushort>(); it != end; ++it, ++iit) 
        *iit = getBGR(maxVal - *it);
}

int main(int argc, char** argv)
{
    Mat gray = imread("gray.tif", IMREAD_ANYDEPTH);

    Mat color(gray.size(), CV_8UC3);

    color_from_gray(gray, color);

    imwrite("color.tif", color);

    return 0;
}
jodis
  • 158
  • 1
  • 8
0

LUT quick and dirty:

Mat gray = imread("gray.tif", IMREAD_ANYDEPTH);
Mat palette = imread("palette.png", IMREAD_COLOR);

Mat color(gray.size(), CV_8UC3);
Vec3b lut[65536];

double scale = (double)palette.rows / 65536;
int i = 0;
for (double x = 1; x <= palette.rows;)
{
    lut[i] = palette.at<Vec3b>((int)x, 0);
    i++;
    x += scale;
}

for (int j = 0; j < gray.rows; j++)//rows
    for (int i = 0; i < gray.cols; i++)//cols
        color.at<Vec3b>(j, i) = lut[gray.at<ushort>(j, i)];

imwrite("color_lut.tif", color);
jodis
  • 158
  • 1
  • 8
  • By "quick and dirty" I mean that you have to make sure that you have the right inputs, i.e. that `gray` is `CV_16UC1`. The code doesn't check for that. – jodis Jun 07 '18 at 21:57