Hi,
This is very neat stuff, very powerful. I just realized (it may be just me that is slow) that the curves can be used to change EV values when developing.
I am not sure that this can be done just by multiplying or dividing the data by constants. I did some tests and although it works there seems to be a color shift for large multipliers/divisors. But for small increase in EV it works nicely. Say multiply by 1.5 or .75 in the code below.
I have hope that it will be possible to figure out curves that develop at various +/- EV and preserve color.
Hopefully these curves could be created on the fly or loaded automatically. That way someone would not have to master the details of using curves to simply brighten up a photo.
Jon
Here is some code. (EDIT:Code improved 5/12/2008)
#define CURVE_SIZE 1024
unsigned short curve[CURVE_SIZE];
void raw_mul(double mult, double offset) {
short i,j;
unsigned short pixVal0, pixVal1, pixVal2;
unsigned char *src;
for(i=0;i<CURVE_SIZE;i++) {
j = (short) (i * mult + offset);
if(j > 1023) j = 1023;
if(j < 0) j = 0;
curve[i] = j;
}
// Set pointer to picture raw data in memory
src = (unsigned char *) hook_raw_image_addr();
// Loop through picture rows
for (i=CAM_RAW_ROWS; i;i-=2){
// Loop through picture columns
for (j=CAM_RAW_ROWPIX; j; j-=8, src+=10){
pixVal0=curve[((0x3fc&(((unsigned short)(*(src+1)))<<2)) | (*(src+0) >> 6))];
*(src+1) = (unsigned char) ((pixVal0>>2)); // 0
pixVal1=curve[((0x3f0&(((unsigned short)(*(src+0)))<<4)) | (*(src+3) >> 4))];
*(src+0) = (unsigned char) ((pixVal0<<6)|(pixVal1>>4)); //0, 1
pixVal2=curve[((0x3c0&(((unsigned short)(*(src+3)))<<6)) | (*(src+2) >> 2))];
*(src+3) = (unsigned char) ((pixVal1<<4)|(pixVal2>>6)); //1,2
pixVal0=curve[((0x300&(((unsigned short)(*(src+2)))<<8)) | (*(src+5)))];
*(src+2) = (unsigned char) ((pixVal2<<2)|(pixVal0>>8)); //2,3 =>(2,0)
*(src+5) = (unsigned char) ((pixVal0)); //3 (=>0)
pixVal0=curve[((0x3fc&(((unsigned short)(*(src+4)))<<2)) | (*(src+7) >> 6))];
*(src+4) = (unsigned char) ((pixVal0>>2)); // 4 => 0
pixVal1=curve[((0x3f0&(((unsigned short)(*(src+7)))<<4)) | (*(src+6) >> 4))];
*(src+7) = (unsigned char) ((pixVal0<<6)|(pixVal1>>4)); // 4,5 => (0,1)
pixVal2=curve[((0x3c0&(((unsigned short)(*(src+6)))<<6)) | (*(src+9) >> 2))];
*(src+6) = (unsigned char) ((pixVal1<<4)|(pixVal2>>6)); // 5,6 => (1,2)
pixVal0=curve[((0x300&(((unsigned short)(*(src+9)))<<8)) | (*(src+8)))];
*(src+9) = (unsigned char) ((pixVal2<<2)|(pixVal0>>8)); // 6,7 =>(2,0)
*(src+8) = (unsigned char) ((pixVal0)); //7 (=>0)
}
for (j=CAM_RAW_ROWPIX; j; j-=8, src+=10){
pixVal0=curve[((0x3fc&(((unsigned short)(*(src+1)))<<2)) | (*(src+0) >> 6))];
*(src+1) = (unsigned char) ((pixVal0>>2)); // 0
pixVal1=curve[((0x3f0&(((unsigned short)(*(src+0)))<<4)) | (*(src+3) >> 4))];
*(src+0) = (unsigned char) ((pixVal0<<6)|(pixVal1>>4)); //0, 1
pixVal2=curve[((0x3c0&(((unsigned short)(*(src+3)))<<6)) | (*(src+2) >> 2))];
*(src+3) = (unsigned char) ((pixVal1<<4)|(pixVal2>>6)); //1,2
pixVal0=curve[((0x300&(((unsigned short)(*(src+2)))<<8)) | (*(src+5)))];
*(src+2) = (unsigned char) ((pixVal2<<2)|(pixVal0>>8)); //2,3 =>(2,0)
*(src+5) = (unsigned char) ((pixVal0)); //3 (=>0)
pixVal0=curve[((0x3fc&(((unsigned short)(*(src+4)))<<2)) | (*(src+7) >> 6))];
*(src+4) = (unsigned char) ((pixVal0>>2)); // 4 => 0
pixVal1=curve[((0x3f0&(((unsigned short)(*(src+7)))<<4)) | (*(src+6) >> 4))];
*(src+7) = (unsigned char) ((pixVal0<<6)|(pixVal1>>4)); // 4,5 => (0,1)
pixVal2=curve[((0x3c0&(((unsigned short)(*(src+6)))<<6)) | (*(src+9) >> 2))];
*(src+6) = (unsigned char) ((pixVal1<<4)|(pixVal2>>6)); // 5,6 => (1,2)
pixVal0=curve[((0x300&(((unsigned short)(*(src+9)))<<8)) | (*(src+8)))];
*(src+9) = (unsigned char) ((pixVal2<<2)|(pixVal0>>8)); // 6,7 =>(2,0)
*(src+8) = (unsigned char) ((pixVal0)); //7 (=>0)
}
}
}