Pointer to different data types

Pages: 12
I have a program using a camera to capture images. I want to be able to use Mono and Color cameras. Not at the same time.
So I have a RGBTRIPLE pointer for color bitmaps and a uint8_t pointer for Mono bitmaps.

So that I don't have to write out my image processing routines twice I would like to have a single pointer that can point to either type of bitmap.

Example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void ProcessImage (RGBTRIPLE *pImage) // pass a pointer to a bitmap
{

   uint8_t *ptr_mono_pixel;
   RGBTRIPLE *ptr_color_pixel;

   if(MonoImage) //check image type
   {
      ptr_mono_pixel = (uint_t8 *) pImage; 
      ....... //continue processing mono bitmap
      ptr_mono_pixel++;
      *ptr_mono_pixel = 128;
      .......
   }
   else 
   {
      ptr_color_pixel = (RGBTRIPLE*) pImage;
      ....... //continue processing color image
      ptr_color_pixel++;
      ptr_color_pixel->rgbtRed = 128;
      .......
   }
} 

The above works but as you can see I have to use two different pointers
and so I have to duplicate the image processing tasks.

What I would like is a single pointer.

Example :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void ProcessImage (void *pImage) // pass a pointer to a bitmap
{

   void *ptr_any_pixel;

   if(MonoImage) //check image type
      ptr_any_pixel = (uint8_t *) pImage; 
   else 
      ptr_any_pixel = (RGBTRIPLE *) pImage;

      ....... //continue processing either type of image
     ptr_any_pixel++;  //will not compile
      .......
 }

Using a void pointer as per above restricts what I can do such as
ptr_any_pixel = ptr_any_pixel + x; // does not compile.
Last edited on
Please, use [.code] at the start of your code and [./code] at the end of it :) ( without the dot )
Last edited on
easy way, just use uint8 for both. the size of an rgb image is just 3x bigger.
if you insist on typing them,

1
2
3
4
5
6
7
8
9
10
11
12
enum imagetype{colored, greyscale};
void ProcessImage (void*pImage, imagetype t) //default t for most common type?
{
    if(t == colored)
          {
          color image code
          }
         else 
    {
      greyscale code
    }
}


you can also overload the functions, unless rgb type is a hidden mask for a char* and it can't tell the diff.

but it sounds like using unsigned char* for both types really is what you want.
Last edited on
Ah, but that was what I was trying to avoid.
My image processing code is pretty much the same for both color
and mono.

But they need different pointers.

I thought if I could assign the pointer according to which camera
is plugged in, I would not have to duplicate the image processing code.
what, exactly, is this:
RGBTRIPLE

its probably avoidable to duplicate the code.
if its just unsigned char[3] you can cast it to just a unsigned char* for both.
Last edited on
This structure describes a color consisting of relative intensities of red, green, and blue. The bmciColors member of the BITMAPCOREINFO structure consists of an array of RGBTRIPLE structures.
 
 typedef struct tagRGBTRIPLE{BYTE rgbtBlue ;BYTE rgbtGreen; BYTE rgbtRed;}RGBTRIPLE;


Members
•rgbtBlue
Specifies the intensity of blue in the color.
•rgbtGreen
Specifies the intensity of green in the color.
•rgbtRed
Specifies the intensity of red in the color.

If I use unsigned char* as a pointer for either the mono or color bitmaps, that will not work either, as the pointer arithmetic will be incorrect when I am dealing with the RGB color bitmap.
Last edited on
if(MonoImage) //check image type This is a hidden, required parameter to ProcessImage. You should pass it explicitly.

If the processing part of the two image types is truly identical except for the pointer type, then create a template function and call it.

But really, you should have an Image class that encapsulates all of this stuff.
typedef struct tagRGBTRIPLE{BYTE rgbtBlue ;BYTE rgbtGreen; BYTE rgbtRed;}RGBTRIPLE;

that is awful ^^
if you don't HAVE to have that thing, I would just say don't use it. Is that an option? You 'could' force 1-byte struct alignment and turn that into effectively char[3] with a pointer, and then mush it all back together, but relying on compiler settings to get the right result is a little fragile. I was hoping it was a typedef for char[3] or the like :(

you certainly can use unsigned char* for both. Yes, you have to adjust your code a little to do that. There is no free lunch on that front, somewhere in the code you have to acknowledge that you have 2 different formats. If time and space for greyscale is not an issue, one way to do things is set RGB equal and have your 'greyscale' images stored as RGB images internally, and only observe a difference between RGB and Greyscale when reading and writing to a file. The rest of the time, no difference.


Am I taking you astray or helping … ?
Last edited on
My image processing code is pretty much the same for both color
and mono.
How come? RGB and gray do not contain the same information. I would expect that you need to convert color to gray before you actually can use it.
if you don't HAVE to have that thing, I would just say don't use it.

Why not? There's no reason for the compiler to pad this structure. On my PC with cygwin and no special options, the struct is 3 bytes:
$ cat foo.cxx 
1
2
3
4
5
6
7
8
9
#include <iostream>

typedef unsigned char BYTE;
typedef struct tagRGBTRIPLE{BYTE rgbtBlue ;BYTE rgbtGreen; BYTE rgbtRed;}RGBTRIPLE;

int main()
{
    std::cout << "sizeof(RGBTRIPLE)=" << sizeof(RGBTRIPLE) << '\n';
}

dave@zaphod ~/tmp
$ make
g++ -Wall -g -D DEBUG -std=c++14 -c foo.cxx
g++ -L. -g foo.o -lm -o foo.exe
rm foo.o

dave@zaphod ~/tmp
$ ./foo
sizeof(RGBTRIPLE)=3

windows doesnt need padding, some os do? or is that a relic of days gone by?
I believe it's a function of the hardware, not the OS. But with all the data items being bytes, there's no extra alignment needed. If you added a 16-, 32-, or 64-bit value, then it would probably pad as needed to align those onto 2- 4- or 8- byte boundaries, and possibly pad the length so that arrays of the struct would preserve the alignment.
ok. well given that, just cast their array back to a unsigned char* if you want to club it to death, but that will still leave you with 2 logics to manage on top of pointer uglies. I still think setting r=g=b = grey may be your best bet for keeping the logic the same most places, and process the greys as if in color like I said above. Its a little wasteful, but it will let you use the same code almost everywhere. If you decide to support rgba you are back to a bit of aggravation.
Last edited on
My image processing code is pretty much the same for both color
and mono.
How come? RGB and gray do not contain the same information. I would expect that you need to convert color to gray before you actually can use it.


Well they are not exactly the same.
Every now and then I have to do a test to see which type of image I am processing.

I only need to do this when reading or writing pixel data.
Following that the processing is the same.
Last edited on
its the other way around. typically you would convert grey to color (to support both types with same code), as I said above… if you have the pixel 123 value in the greyscale, set R = 123, G=123, and B = 123. Then process everything as if it were colored, and all the code is the same for both (except, you cannot use color modifying operations on greys, … you *could* but the results would be very weird).

its the other way around. typically you would convert grey to color (to support both types with same code), as I said above… if you have the pixel 123 value in the greyscale, set R = 123, G=123, and B = 123. Then process everything as if it were colored, and all the code is the same for both


Yes I thought about doing this.
Two problems.
1) The cameras have different pixel formats
mono is 2088x1088, 1 byte per pixel, while the color image is 1294x964,
3 bytes per pixel.
I'm not using the total image area in either case so I could just load up the
first 1.2Mpixels (3.7Mbytes) in the color image with grayscale data as you suggest.
2) This could be slow. At present, the program only runs the color code for the color image and only runs the grayscale code for the grayscale image, so no time penalty. To transfer 3.7Mbytes would take some time.
Last edited on
right, you have to take the camera's greyscale 1-byte and bloat it up when you read it to do that. And you likely will write it back out as 1-byte format as well just because no one wants a triple sized image file for no reason.

2) yea it "could" be slower. That is the trade off. If you want to use the same code on both formats, you may willingly pay this price. Its no slower than your color image processing, so if that is fast enough...

I don't know 100% what you are trying to do. If you are transmitting a bunch of images over a slow connection, you can't bloat it up for sure. If you are processing it on slower embedded hardware, or trying to reduce battery usage, it may not be a great answer there either (even if its fast enough, doing ~3 times the work all the time burns cpu which burns battery faster). Its just 'an' answer. It may simply be that you need color and grey versions of your functions, and live with that. That gets you the performance, at the cost of a bit more code.

the different resolutions should not matter (very much). an RGB processing function could have the image data pointer, the # of rows, and the # of columns coming into it. That would work on both image types if you did the bloat approach, just pass in the resolution along with the data.
Last edited on
@ Jonnin

Actually that might be tricky because when I am using a monochrome camera
the color bitmap does not exist.

I have an industrial machine vision application. This has been running for
several years using a color camera(s) only. The machine is examining Product
A, at a rate of 12 frames per second. It then performs image analysis and
from that determines where the product is to be placed along the length of
the machine.

Now I want to use that process to do the same thing with product B. However,
without getting into details, Product B requires a monochrome camera.

Now I don't want to have two different apps. I could use compiler directives to
compile one way or the other. However I prefer not to do that. I have made the
program automatically detect which camera is plugged in and change the
parameters accordingly.

The cameras use USB3 interface and with their driver, images are captured
following either a hardware or software trigger. The camera driver then places
the image in the PC memory and supplies a pointer to that image in a callback
routine. The type of image pointed to is a function of the camera. The color
camera places a color bitmap in memory, while the mono camera places a
grayscale bitmap in memory.

So when using the mono camera, the color bitmap that you suggest I poke
with grayscale values, does not actually exist.

I could create a couple of RGBTriple bitmaps purely for that purpose, but again
it all gets messy.

Also I not only read information from the bitmaps but I am also writing pixel
data back to the bitmap. If I do as you suggest, I could read the grayscale
data from the color bitmap (that has been pre-loaded with grayscale info), but
I would still need a single byte pointer to write pixel data back to the grayscale
image.

My purpose in starting this thread was that I thought there may be a simple
way to overload a pointer so that it could point to different data types of
differing length.

Using a void pointer does that but then pointer arithmetic is not available,
which is essential when seeking various areas of interest in the image bitmaps.

Now because no one has come up with the simple answer, I assume that there
is no such simple answer.

Consider this....
1
2
3
4
5
6
7
8
9
10
11
12
13
void Process Image (*pImage)
{

   void ptr_anything;

   If (ImageIsMono) ptr_anything = (uint8_t *) pImage;
   else ptr_anything = (RGBTriple *) pImage;

   // processing image.....
   ptr_anything++;            // does not compile
   // more processing....
}
 


With the above, I can see that at compile time, the compiler does not know
SizeOf the pointer so cannot increment it at line 11. However at run time, the
SizeOf the data pointed to would be known because I set it prior to the
increment. But I guess the compiler manufacturer has to make this illegal as
they cannot depend on the coder always ensuring the pointer has been
assigned.

Now Consider this....
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Process Image (*pImage, int i)
{

   uint8_t * ptr_monoBitmap;
   RGBTriplet * ptr_colorBitmap;

   If (ImageIsMono) 
   {
       ptr_monoBitmap = (uint8_t *) pImage;
       // processing image.....
       ptr_monoBitmap = ptr_monoBitmap + i;            // does compile
      // more processing....
    }
    else 
    {
        ptr_colorBitmap = (RGBTriple *) pImage;
        // processing image.....
        ptr_colorBitmap = ptr_colorBitmap + i;            // does compile
       // more processing....
     }
}
 


With the above the pointer arithmetic does compile even though 'i' is unknown
at compile time.

This works I guess because the compiler knows the SizeOf the data pointed
at by the pointers, and of course, the SizeOf int is also known.
Last edited on
there is no simple answer. You can do it any number of ways but its going to take hacking on the code. You have several choices... but most of the clean ones are going to involve a bit of rewriting. if that is a no-go, there are any number of low level band-aids you can use too.


void pointers can't be used directly in c++, they really just a transport mechanism. You have to cast them sometype* st = (sometype*)(vp); st++; //ok.
and a bit of smoke and mirrrors... everything is stored as bytes one way or another, so to make it work with a single cast VP back to something you can club to death:

int offset;
offset = sizeof(something);
if(otherthing) offset=sizeof(othertype); //etc for all the supported things.

unsigned char* uc = (unsigned char*)(vp);
vp+= offset; //++ for bytes, += 3 for RGB, etc

this is crude low level stuff. Its not recommended unless there is no other way. But it will work.


Last edited on
Thanks for all the help.

I think I will stick with what I have.

It works and it is easy to follow.

I just have to write some parts of the code twice.

Pages: 12