histogram work wrong when viewport width and buffer width are diffrent - General Discussion and Assistance - CHDK Forum
supplierdeeply

histogram work wrong when viewport width and buffer width are diffrent

  • 6 Replies
  • 5250 Views
Advertisements
it seem the histogram code do not check every pixel.see code of important steps.

Code: [Select]
void histogram_process()
{
    static unsigned char *img;
    int i, hi, c;
    int y, v, u;
static int x, img_offset;
    static int viewport_size;
    unsigned int histo_fill[5];

   switch (histogram_stage) {
        case 0:
            img=((mode_get()&MODE_MASK) == MODE_PLAY)?vid_get_viewport_fb_d():((kbd_is_key_pressed(KEY_SHOOT_HALF))?vid_get_viewport_fb():vid_get_viewport_live_fb());

         if (img==NULL){
     img = vid_get_viewport_fb();
   }
img_offset = vid_get_viewport_image_offset(); // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
            viewport_size = vid_get_viewport_height() * vid_get_viewport_buffer_width();
            for (c=0; c<5; ++c) {
                for (i=0; i<HISTO_WIDTH; ++i) {
                    histogram_proc[c][i]=0;
                }
                histo_max[c] = histo_max_center[c] = 0;
            }

            histogram_stage=1;
            break;

        case 1:
        case 2:
        case 3:
x = 0;
int l = 11;
            for (i=(histogram_stage-1)*6; i<viewport_size*3; i+=6*3*2) {
                y = img[img_offset+i+1];
                u = *(signed char*)(&img[img_offset+i]);
                if (u&0x00000080) u|=0xFFFFFF00;
                v = *(signed char*)(&img[img_offset+i+2]);
                if (v&0x00000080) v|=0xFFFFFF00;

                hi = y*HISTO_WIDTH/256; // Y
                ++histogram_proc[HISTO_Y][hi];
                hi = clip(((y<<12)          + v*5743 + 2048)/4096)*HISTO_WIDTH/256; // R
                ++histogram_proc[HISTO_R][hi];
                hi = clip(((y<<12) - u*1411 - v*2925 + 2048)/4096)*HISTO_WIDTH/256; // G
                ++histogram_proc[HISTO_G][hi];
                hi = clip(((y<<12) + u*7258          + 2048)/4096)*HISTO_WIDTH/256; // B
                ++histogram_proc[HISTO_B][hi];

// Handle case where viewport memory buffer is wider than the actual buffer.
x++;
if (x == vid_get_viewport_width())
{
i += vid_get_viewport_row_offset();
x = 0;
}
}

            ++histogram_stage;
            break;

for (i=(histogram_stage-1)*6; i<viewport_size*3; i+=6*3*2) {

this do i+=6*3*2 step of 36.there are 3 steps used to calculate and 3 bytes per pixel = 36/9

so only every 4. pixel in the display buffer is check.also the beginning is shift more.(histogram_stage-1)*3 is ok i think.but its
(histogram_stage-1)*6


but the bigges problem i find is that line

   // Handle case where viewport memory buffer is wider than the actual buffer.
            
   x++;
            if (x == vid_get_viewport_width())
            {
               i += vid_get_viewport_row_offset();
               x = 0;
            }

it count to vid_get_viewport_width = 360 on my camera in 4:3 shooting mode and add a offset.but this skip
more data in wrong way.Here is a fix from philmoz i use, so zebra mode/edge overlay work correct.

http://chdk.setepontos.com/index.php?topic=5967.msg62178#msg62178

but i think with histogram this do not work, because

i+=6*3*2 read then wrong data and x=360 is reach when 12960 is value of i.this are 4 lines.

because on ixus 1000 in 4:3 shooting mode, pixels 0-60 and 320-480 contain no valid data and should be skip.
Is it not possible for speed to use all pixels for histogram with new Camera ?

My camera have for X resolution 3640 Pixels, 360 /4 is 90 pixels,
If less than 40 pixels are overexposure, histogram do not detect that.

If camera is not fast enough, maybe somebody can enhance the x offset code.
I think there need change the line to

if (x == (vid_get_viewport_width()/4))

but i dont know if the

i=(histogram_stage-1)*6

is ok, so i think there need some pixels subtract

maybe this is ok

or the code can rewritten to look more easy in

a for next loop for y
and a for next loop for x

Or what can do better to get it working ?
« Last Edit: 13 / March / 2011, 05:27:13 by Bernd R »
Ixus 1000 HS

*

Offline philmoz

  • *****
  • 3450
    • Photos
Yes, there is a mistake here, the line:
    x++;
should be:
    x += 12;

Viewport buffer memory does not store image data as 3 bytes per pixel like the bitmap buffers do.The viewport stores 4 image pixels in each 6 byte block memory. It is stored as UYVYYY where Y = luminance data for 1 pixel and U & V are chrominance data for the block of four pixels.

This is why the histogram has the *6 multiplier. If you change it to *3 you will be processing a YYY block as though it were UYV block which will give incorrect results.

The histogram logic is examining 3 out of every 24 viewport pixels horizontally (every iteration of the for loop jumps by 36 bytes which is 6 lots of 6 bytes, and each 6 bytes stores 4 pixels). This is done with the combination of the histogram_stage variable taking the values 1, 2 & 3 and the for loop.
The histogram calculation could be made more accurate and look at more data; but it will take longer to calculate.

Phil.
CHDK ports:
  sx30is (1.00c, 1.00h, 1.00l, 1.00n & 1.00p)
  g12 (1.00c, 1.00e, 1.00f & 1.00g)
  sx130is (1.01d & 1.01f)
  ixus310hs (1.00a & 1.01a)
  sx40hs (1.00d, 1.00g & 1.00i)
  g1x (1.00e, 1.00f & 1.00g)
  g5x (1.00c, 1.01a, 1.01b)
  g7x2 (1.01a, 1.01b, 1.10b)

@philmoz

thanks for your fix, i test and it work ok, the overexpose and underexpose markers show now in 4:3 shooting mode same as 16:9 shooting mode.

UYVyyy
As i understand your text correct the 3 yyy values are not count.
To make it more precise to overexpose, there can check for highest Y value and only the highest value is calc with u and v

Can you please check, if your propset 4 Camera have on prop value 200 a overexpose Value show ?
My Ixus 1000 use propset 4 and show on prop 200 a value, that seem show how many pixels are overexpose.

and when i look at this value, i see that it show around 300-500 and only if more i see overexpose sign from chdk histogram.when overexpose sign in chdk is not show, then the shootet images are always a little overexpose, on RAW not so much as on jpg.but when i look that prop value 200 is 0, then pictures are good.

only bad thing with this prop 200 value is, that when press shoot button half, the value is not update then.only when shoot button is release, it is update.But when shoot button is release, Canon Firmware do not use the ev value.only when press shoot half ev value is use in Display.

Maybe you can tell how i can change that the overexpose sign on histogram is set, when a value is over 230.so its not so important if the overexpose check is not do on all pixels.

I set the ignore boundary peek value to 0 and later to 32, but it do not help.

I see always upto 500 in prop 200 value and Histogram show no overexpose.
« Last Edit: 13 / March / 2011, 10:37:06 by Bernd R »
Ixus 1000 HS

*

Offline philmoz

  • *****
  • 3450
    • Photos
UYVyyy
As i understand your text correct the 3 yyy values are not count.
To make it more precise to overexpose, there can check for highest Y value and only the highest value is calc with u and v

The diagram below shows the values that are used for the first two 'for' loop iterations at each value of histogram_stage. As you can see only 1 of each 24 Y values are examined at each 'histogram_stage', across the three stages 3 of each 24 Y values get processed. You could reduce the 6*3*2 multiplier in the for loop to 6*3 which would double the number of Y values checked (you would also need to change x += 12 to x += 6).

As you said you could also find the max Y value from each group of four; but this is then going to bias the histogram to the right. Maybe an average of the four Y values would be better.

All of this will of course mean the histogram calculation will take longer.

Code: [Select]
histogram_stage
       1         xxx                                       xxx
       2                xxx                                       xxx
       3                       xxx                                       xxx
viewport data -> UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY UYVYYY
Quote
Can you please check, if your propset 4 Camera have on prop value 200 a overexpose Value show ?
My Ixus 1000 use propset 4 and show on prop 200 a value, that seem show how many pixels are overexpose.

The G12 has this prop 200 value which does appear to relate to the image brightness; but I can't say if it would be of any use for determining overexposure. As you say it does not get updated when you press the shutter, it only appears to be set when the live view is displayed. You may need to find where the property is set or used in the firmware to work out its function.

The histogram code has very little documentation I can find so I'm not sure of the logic and reasoning behind the over and under exposure warnings.

Phil.
CHDK ports:
  sx30is (1.00c, 1.00h, 1.00l, 1.00n & 1.00p)
  g12 (1.00c, 1.00e, 1.00f & 1.00g)
  sx130is (1.01d & 1.01f)
  ixus310hs (1.00a & 1.01a)
  sx40hs (1.00d, 1.00g & 1.00i)
  g1x (1.00e, 1.00f & 1.00g)
  g5x (1.00c, 1.01a, 1.01b)
  g7x2 (1.01a, 1.01b, 1.10b)


The G12 has this prop 200 value which does appear to relate to the image brightness; but I can't say if it would be of any use for determining overexposure. As you say it does not get updated when you press the shutter, it only appears to be set when the live view is displayed. You may need to find where the property is set or used in the firmware to work out its function.

My test show, it show very exact overexpose.I notice when use fastev switch option, exposure is too ok, when shutter is release.so when i press shutter half modify exposure with wheel so when release shutter prop 200 show 0, then image is best exposure.but fast ev switch does not modify Canon ev display.

maybe i should test chdk so that fastev switch work too with wheel when no shoot half is press.

I dont know, how i can find code in Canon Formware that access a prop value.
But if somebody can tell how this can do, i can look for codeplace of prop 200 write.
Ixus 1000 HS

*

Offline Lebeau

  • ***
  • 187
I don't know if my code version could be helpfull in your case.
Code: [Select]
void histogram_process()
{
    static unsigned char *img;
    register int i, c, col, row;
    int hi;
    int y, v, u;
    int triplets_in_bytes;
    static int row_offset, col_offset, buffer_width;
    static int viewport_width;
    static int viewport_height;
    unsigned int histo_fill[5];

    switch (histogram_stage) {
        case 0:
            img=((mode_get()&MODE_MASK) == MODE_PLAY)?vid_get_viewport_fb_d():((kbd_is_key_pressed(KEY_SHOOT_HALF))?vid_get_viewport_fb():vid_get_viewport_live_fb());

        if (img==NULL){
      img = vid_get_viewport_fb();
    }
buffer_width = vid_get_viewport_buffer_width ( ); // upon camera viewport buffer, in triplets
row_offset = vid_get_viewport_yoffset ( ); // upon camera aspect ratio, in row
col_offset = vid_get_viewport_xoffset ( ); // upon camera aspect ratio, in triplets
            viewport_height = vid_get_viewport_height(); // in row
            viewport_width = vid_get_viewport_width(); // in triplets
            for (c=5; c--; ) {
                for (i=HISTO_WIDTH; i--; ) {
                    histogram_proc[c][i]=0;
                }
                histo_max[c] = histo_max_center[c] = 0;
            }

            histogram_stage=1;
            break;

        case 1:        case 2:        case 3:
        case 4:        case 5:        case 6:
// for each viewport row
for ( row = viewport_height; row--; )
{
// for each viewport column, interlaced upon histogram_stage, in triplets
for ( col = ( histogram_stage-1 ); col < viewport_width; col += ( 6 * 2 ) )
{
triplets_in_bytes = 3 // numbers of bytes per triplets
* ( buffer_width // memory buffer containing viewport triplets and more, upon camera
* ( row_offset // empty rows, at the top the buffer, upon aspect ratio
+ row )
+ ( col_offset // empty columns, at the left of the buffer, upon aspect ratio
+ col )
);
        y = img [ triplets_in_bytes + 1 ];
                u = * ( signed char * ) ( &img [ triplets_in_bytes ] );
                if ( u & 0x00000080 ) u |= 0xFFFFFF00;
                v = * ( signed char * ) ( &img [ triplets_in_bytes + 2 ] );
                if ( v & 0x00000080 ) v |= 0xFFFFFF00;

hi = ( y * HISTO_WIDTH ) >> 8; // Y
++histogram_proc [ HISTO_Y ] [ hi ];
hi = ( clip ( ( ( y << 12 ) + v * 5742 + 2048 ) >> 12 ) * HISTO_WIDTH ) >> 8; // R
++histogram_proc [ HISTO_R ] [ hi ];
hi = ( clip ( ( ( y << 12 ) - ( u * 1410 + v * 2925 ) + 2048 ) >> 12 ) * HISTO_WIDTH ) >> 8; // G
++histogram_proc [ HISTO_G ] [ hi ];
hi = ( clip ( ( ( y << 12 ) + u * 7258 + 2048 ) >> 12 ) * HISTO_WIDTH ) >> 8; // B
++histogram_proc [ HISTO_B ] [ hi ];
}
;
}
;
            ++histogram_stage;
            break;

        case 7:
            for (i=HISTO_WIDTH; i--; ) { // G
                histogram_proc[HISTO_RGB][i]=histogram_proc[HISTO_R][i]+histogram_proc[HISTO_G][i]+histogram_proc[HISTO_B][i];
            }
            for (c=5; c--; ) { // calculate maximums
                for (i=HISTO_WIDTH; i--; ) {
                    if (histo_max[c]<histogram_proc[c][i])
                        histo_max[c]=histogram_proc[c][i];
                    if (histo_max_center[c]<histogram_proc[c][i] && i>=conf.histo_ignore_boundary && i<HISTO_WIDTH-conf.histo_ignore_boundary)
                        histo_max_center[c]=histogram_proc[c][i];
                }

                if (histo_max[c] > 0) {
                    histo_max_invw[c] = ((float)HISTO_HEIGHT)/histogram_transform((float)histo_max[c]);
                } else {
                    histo_max_invw[c] = 0.0f;
                }

                if (histo_max_center[c] > 0) {
                    histo_max_center_invw[c] = ((float)HISTO_HEIGHT)/histogram_transform((float)histo_max_center[c]);
                } else {
                    histo_max_center_invw[c] = 0.0f;
                }
            }

            if (histo_max[HISTO_RGB] > 0) { // over- / under- expos
                under_exposed = ((histogram_proc[HISTO_RGB][0]<<3)
                                +(histogram_proc[HISTO_RGB][1]<<2)
                                +histogram_proc[HISTO_RGB][2]) > exposition_thresh;

                over_exposed = (histogram_proc[HISTO_RGB][HISTO_WIDTH-3]
                               +(histogram_proc[HISTO_RGB][HISTO_WIDTH-2]<<2)
                               +(histogram_proc[HISTO_RGB][HISTO_WIDTH-1]<<3)) > exposition_thresh;
            } else {
                over_exposed = 0;
                under_exposed = 1;
            }

            histogram_stage=8;
            state_expos_recalculated = 1;
            break;

        case 8:
            for (c=5; c--; ) {
                histo_fill[c]=0;
                for (i=HISTO_WIDTH; i--; ) {
                    histogram[c][i] = (histogram_transform((float)histogram_proc[c][i]))*histo_max_center_invw[c];
                    if (histogram[c][i] > HISTO_HEIGHT)
                        histogram[c][i] = HISTO_HEIGHT;
                    histo_fill[c]+=histogram[c][i];
                }
            }

            if (conf.histo_auto_ajust) {
                histo_magnification = histo_fill[histo_main]*1000/(HISTO_HEIGHT*HISTO_WIDTH);
                if (histo_magnification<200) { // try to ajust if average level is less than 20%
                    histo_magnification=200*1000/histo_magnification;
                    for (c=5; c--; ) {
                        for (i=HISTO_WIDTH;i--; ) {
                            histogram[c][i] = (histogram_transform((float)histogram_proc[c][i]))*histo_max_center_invw[c]*histo_magnification/1000;
                            if (histogram[c][i] > HISTO_HEIGHT)
                                histogram[c][i] = HISTO_HEIGHT;
                        }
                    }
                } else
                    histo_magnification=0;
            } else {
                histo_magnification=0;
            }

            histogram_stage=0;
            break;

        case HISTOGRAM_IDLE_STAGE:
            break;
    }

}

@Lebeau
>I don't know if my code version could be helpfull in your case.

thanks for your code, i test later.Your code look more precise.

I test a little with values and i see when i lower the (v>255) then i get overexpose flag good show

maybe there can add a overexpose threshhold in GUI that change this value, for histogram too.In zebra there is such a value.I need set this to 10.but for histogram i need 230, maybe yuv is little diffrent as rgb.

static int clip(int v) {
    if (v<0) v=0;
    if (v>230) v=255;
    return v;
}
Ixus 1000 HS

 

Related Topics