Victor Image Processing Library How-to Tips

Load a 16-bit Grayscale TIFF Image

The Victor Image Processing Library will load 16-bit images, but processing functions do not directly operate on 16-bit images. The 16-bit image has to be converted to 8-bit for other functions to access them.

The loading of the 16-bit image is straight forward. In general, the steps are:

Under ideal conditions, the 16-bit data are converted directly to 8-bit with a sequence like:

But many times the 16-bit image does not contain data that uses the entire 16 bits. Often you will find 10- or 12-bit data saved in the 16-bit format because there is no 10- or 12-bit format.

In this case, the data have to be expanded so that the 8-bit image fully represents the original data. The Victor Library function

int convertgray16to8ex(int min, int max, ref imgdes srcimg, ref imgdes resimg);

where min and max represent the values in the original 16-bit image to be expanded to fit the 0 to 255 8-bit data range.

Without any expansion, the conversion from 16- to 8-bit is done by keeping only the upper byte of the 16-bit value and assigning it to the single byte of the 8-bit value. A 16-bit value of 0xffff (65535, the maximum 16-bit value) becomes the 8-bit value 0xff (255, the maximum 8-bit value).

If the original data only cover 10-bits of range, then the maximum possible 10-bit value is 0x3ff, so expansion of the data should be between 0 and 0x3ff (1023);

In the example below, the function loadimagefile tests for and loads several different file types. When it encounters a tiff file that appears to be 16-bit grayscale it tests for the minimum and maximum values in the 8-bit data and determines the maximum pixel depth in the original file and expands the data as it converts it to 8-bit.



Load 16-bit Grayscale - the C# Source Code

Requires Victor Image Processing Library for 32-bit Windows v 6 or higher.
       [DllImport("vic32.dll", EntryPoint = "convertgray16to8ex")]
       unsafe public static extern int convertgray16to8ex(int min, int max, ref vicwin.imgdes srcimg, ref vicwin.imgdes resimg);
      public static int loadimagefile(string filename, ref vicwin.imgdes timage) 
      {
        vicwin.BITMAPINFOHEADER bdata; 
        vicwin.GifData gdata; 
        vicwin.JpegDataEx jdata; 
        vicwin.TiffDataEx tdata; 
        vicwin.PngData pdata;
        vicwin.TgaData tgadata;
        int rcode;
        int length, width, vbitcount;
        string fileType; 
        string filetype; 
        vicwin.imgdes newimage; 
        vicwin.imgdes tempimage;
        vicwin.imgdes tempimage8;
        int xres; 
        int yres; 
        int resunit; 
         newimage = new vicwin.imgdes();
         tempimage = new vicwin.imgdes();
         tempimage8 = new vicwin.imgdes();
         bdata = new vicwin.BITMAPINFOHEADER(); 
         gdata = new vicwin.GifData(); 
         jdata = new vicwin.JpegDataEx(); 
         tdata = new vicwin.TiffDataEx();
         tgadata = new vicwin.TgaData();
         pdata = new vicwin.PngData(); 
         
        // Initialize variables
 
        rcode = vicwin.BAD_FTPE;
        // Identify file type and get information about the file to load
        fileType = filename.Substring(filename.LastIndexOf(".")+1, 3);
        filetype = fileType.ToLower();
        int totalpages; 
        int  arrayelems; 
        int  pageIndex;
        switch (filetype)
        {
            case "bif":
                width = timage.endx + 1;
                length = timage.endy + 1;
                vbitcount = 8;
                rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
                if (rcode == vicwin.NO_ERROR)
                    rcode = vicwin.loadbif(ref filename, ref tempimage);
                break;
            case "bmp":
                rcode = vicwin.bmpinfo(ref filename, ref bdata);
                width = bdata.biWidth;
                length = bdata.biHeight;
                vbitcount = bdata.biBitCount;
                if (vbitcount == 32 || vbitcount == 16) // 16- and 32-bit images go into 24-bit rgb image buffers
                    vbitcount = 24;
                rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
                if (rcode == vicwin.NO_ERROR)
                    rcode = vicwin.loadbmp(ref filename, ref tempimage);
                break;
            case "gif":
                rcode = vicwin.gifinfo(ref filename, ref gdata);
                width = gdata.width;
                length = gdata.length;
                vbitcount = gdata.vbitcount;
                rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
                if (rcode == vicwin.NO_ERROR)
                    rcode = vicwin.loadgif(ref filename, ref tempimage);
                break;
            case "jpg":
                rcode = vicwin.jpeginfoex(ref filename, ref jdata);
                width = jdata.width;
                length = jdata.length;
                vbitcount = jdata.vbitcount;
                rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
                if (rcode == vicwin.NO_ERROR)
                    rcode = vicwin.loadjpg(ref filename, ref tempimage);
                break;
            case "png":
                rcode = vicwin.pnginfo(ref filename, ref pdata);
                width = pdata.width;
                length = pdata.length;
                vbitcount = pdata.vbitcount;
                vicwin.imgdes whitebackgroundimage;
                rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
                if (rcode == vicwin.NO_ERROR)
                    if (pdata.colorType == 4 || pdata.colorType == 6)
                    { // alpha channel present
                        whitebackgroundimage = new vicwin.imgdes();
                        rcode = vicwin.allocimage(ref tempimage8, width, length, 8);
                        rcode = vicwin.loadpngwithalpha(ref filename, ref tempimage, ref tempimage8);
                        rcode = vicwin.negative(ref tempimage8, ref tempimage8);
                        rcode = vicwin.allocimage(ref whitebackgroundimage, width, length, vbitcount);
                        rcode = vicwin.zeroimage(255, ref whitebackgroundimage);
                        rcode = vicwin.wtaveragemask(ref tempimage, ref whitebackgroundimage, ref tempimage, ref tempimage8);
                        vicwin.freeimage(ref tempimage8);
                        vicwin.freeimage(ref whitebackgroundimage);
                    }
                    else
                    {
                        rcode = vicwin.loadpng(ref filename, ref tempimage);
                    }
                break;
            case "tga":
                rcode = vicwin.tgainfo(ref filename, ref tgadata);
                width = tgadata.width;
                length = tgadata.length;
                vbitcount = tgadata.vbitcount;
                rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
                if (rcode == vicwin.NO_ERROR)
                    if (tgadata.ABPerPix == 8)
                    { // alpha channel present
                        string fn = "alpha.tif";
                        rcode = vicwin.allocimage(ref tempimage8, width, length, 8);
                        rcode = vicwin.zeroimage(255, ref tempimage8);
                        rcode = vicwin.loadtgawithalpha(ref filename, ref tempimage, ref tempimage8);
                        rcode = vicwin.savetif(ref fn, ref tempimage8, 0);
                        vicwin.freeimage(ref tempimage8);
                    }
                    else
                    {
                        rcode = vicwin.loadtga(ref filename, ref tempimage);
                    }
                break;
            case "tif":
                int pp = 0;
                arrayelems = 0;
                xres = 0;
                yres = 0;
                resunit = 0;
                totalpages = 0;
                rcode = vicwin.tiffgetpageinfo(ref filename, ref totalpages, ref pp, arrayelems);
                pageIndex = 0;
                if (totalpages > 1)
                { // Ask user what page to load
                    vic_comparator.inputform inputform = new vic_comparator.inputform("tiffpage", totalpages - 1);
                    if (inputform.ShowDialog() == DialogResult.OK)
                    {
                        pageIndex = inputform.val1;
                    }
                }
               rcode = vicwin.tiffinfopagebyindexex(ref filename, ref tdata, pageIndex);
        // To do . . . if xres != yres, resize image to create square pixels
               xres = tdata.xres;
               yres = tdata.yres;
               resunit = tdata.resunit;
               width = tdata.width;
               length = tdata.length;
               vbitcount = tdata.vbitcount;
               rcode = vicwin.allocimage(ref tempimage, width, length, vbitcount);
               if (rcode == vicwin.NO_ERROR)
               {
                   rcode = vicwin.loadtifpagebyindex(ref filename, ref tempimage, pageIndex);
        // 16-bit grayscale
                   if ((rcode == vicwin.NO_ERROR || rcode == vicwin.BAD_DATA) && tdata.BitsPSample == 16 && tdata.SamplesPPixel == 1)
                   {
                       int min = 0;
                       int max = 0;
                       int hival = 0;
                       int bittester = 128;  // 1000 0000
                       int shifter = 8;
                       rcode = vicwin.allocimage(ref newimage, width, length, 8);
                       rcode = vicwin.convertgray16to8(ref tempimage, ref newimage);
        // in case the 16-bit grayscale is holding less than 16 bits of real image data, expand contrast so we can view image
                       rcode = calcminmax_gray(ref min, ref max, ref newimage);  // defined below  
                       if(max < 255)
                       {
        // find highest bit set and set the expand contrast hival e.g., if max = 31 - 63, then hival = 0x3ff
                           while (hival == 0 && shifter >= 0)
                           {
                               if ((max & bittester) == bittester)
                                   hival = (0xff << shifter) | 0xff;
                               bittester = bittester >> 1;
                               shifter--;
                           }
                           rcode = convertgray16to8ex(0, hival, ref tempimage, ref newimage);
                       }
                       vicwin.freeimage(ref tempimage);
                       vicwin.copyimgdes(ref newimage, ref tempimage);
                   }
               }
               break;
                   }
            
         if (rcode == vicwin.BAD_DATA)
             rcode = vicwin.NO_ERROR;
         if (rcode == vicwin.NO_ERROR)
            vicwin.copyimgdes(ref tempimage, ref timage);
        return (rcode);
      }
      
       public static int calcminmax_gray(ref int min, ref int max, ref vicwin.imgdes srcimg)
       {
           int[] redtab = new int[256];
           int[] grntab = new int[256];
           int[] blutab = new int[256];
           int j;
           int rcode;
           rcode = vicwin.calchisto(ref srcimg, ref redtab[0], ref grntab[0], ref blutab[0]);
           if (rcode == vicwin.NO_ERROR)
           {
               for (j = 255; j > 0; j--)
               {
                   if (redtab[j] > 0)
                   {
                       max = j;
                       break;
                   }
               }
               for (j = 0; j < 255; j++)
               {
                   if (redtab[j] > 0)
                   {
                       min = j;
                       break;
                   }
               }
           }
           return rcode;
       }
      
Victor Image Processing Library

Victor Image Processing Library homepage | Victor Product Summary | more source code




Copyright © 1995 - 2013 Catenary Systems Inc. All rights reserved. Victor Image Processing Library is a trademark of Catenary Systems.