apps/png/pnghist_nocgi.c

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <unistd.h>
00004 #include <sys/ioctl.h>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <fcntl.h>
00008 #include <math.h>
00009 
00010 #include <asm/elphel/autoexp.h>
00011 #include <asm/elphel/hist.h>
00012 
00013 #include <sys/mman.h>
00014 #include <asm/elphel/c313a.h>
00015 
00016  
00017 //#include "zlib.h"
00018 #include "libpng/png.h"
00019 //#define PNGHISTDEBUG 1
00020 #define HIST_SIZE 256 * 4 * 4
00021 
00022 #define HPNG_PLOT_BARS    1
00023 #define HPNG_CONNECT_DOTS 2
00024 #define HPNG_FILL_ZEROS   4
00025 #define HPNG_LIN_INTERP   8
00026 #define HPNG_RUN_SQRT     16
00027 struct autoexp_t autoexp;
00028 int write_png(char *file_name, int height, int data[1024], int mode, int colors);
00029 int main(argc, argv)
00030     int argc;
00031     char *argv[];
00032 {
00033   int hists[1536];
00034   int rava[256];
00035 //  int fd;
00036   int autoexp_fd;
00037   int i,j,k,a,l;
00038 //  short int hsz[2];
00039   double dscale,dcoeff;
00040   int coeff;
00041   int png_height;
00042   int ww,wh;
00043   int devfd;
00044   int mode;
00045   int colors=57; // colors 1 - r, 2 - g1, 4 - g2, 8 - b, 16 - w, 32 - g1+g2 
00046   int lastmiddle_i,newmiddle_i;
00047   int rav=0; // running average
00048   int z;
00049   void *_map;  
00050   const char colors_calc[]={  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,0xa,0xb,0xc,0xd,0xe,0xf,
00051                       0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
00052                         6,  7,  6,  7,  6,  7,  6,  7,0xe,0xf,0xe,0xf,0xe,0xf,0xe,0xf,
00053                       0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf};
00054   if (argc<5) {printf("pnghist height scale mode colors average"); return 0;}
00055   png_height=atoi(argv[1]);
00056   if (png_height>256) png_height=256;
00057   dscale=atof(argv[2]);
00058   mode=atoi(argv[3]);
00059   colors=atoi(argv[4]) & 0x3f;
00060   
00061  
00062   rav=atoi(argv[5]);
00063   
00064  
00065   if ((devfd = open("/dev/ccam_img", O_RDONLY)) < 0) {printf("Device busy (%s)\r\n", "/dev/ccam_img"); return -1;}
00066 
00067   ww=ioctl(devfd, _CCCMD( CCAM_RPARS , P_ACTUAL_WIDTH), 0);
00068   wh=ioctl(devfd, _CCCMD( CCAM_RPARS , P_ACTUAL_HEIGHT), 0);
00069   close (devfd);
00070 //  printf ("w=%d, h=%d\n",ww,wh);
00071   
00072 //  autoexp_fd = open(AUTOEXP_DEV_NAME, O_RDWR);
00073   autoexp_fd = open(AUTOEXP_DEV_NAME, O_RDONLY);
00074   if(autoexp_fd < 0) {
00075      printf("open %s failed - may be busy, or not started\r\n", AUTOEXP_DEV_NAME);
00076      return -1;
00077   }
00078   z = ioctl(autoexp_fd, _IO(IOC_AUTOEXP_GET, 0x00), &autoexp);
00079   
00080   
00081 //  if((_map = mmap(NULL, HIST_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, autoexp_fd, 0)) == MAP_FAILED) {
00082   if((_map = mmap(NULL, HIST_SIZE, PROT_READ, MAP_FIXED | MAP_SHARED, autoexp_fd, 0)) == MAP_FAILED) {
00083      printf("mmap %s failed - may be busy, or not started\r\n", AUTOEXP_DEV_NAME);
00084      return -1;
00085   }
00086   memcpy (hists,_map,HIST_SIZE);
00087   close (autoexp_fd);
00088 #if 0  
00089   fd = open("/tmp/histogram", O_RDONLY);
00090   if(fd <= 0) {
00091       printf("No histogram file (%s)\r\n", "/tmp/histogram");
00092       return -1;
00093   }
00094   read(fd, hsz, 4);
00095   ww=(ww*hsz[0])/100;
00096   wh=(wh*hsz[1])/100;
00097   read(fd, hists, HIST_SIZE);
00098   close (fd);
00099 #endif  
00100   ww=(ww*autoexp.width)/100;
00101   wh=(wh*autoexp.height)/100;
00102   dcoeff=(png_height*1024)/(dscale*ww*wh);
00103   coeff=dcoeff*65536;
00104 #ifdef PNGHISTDEBUG
00105   printf ("w=%d, h=%d\n",ww,wh);
00106   for (i=0;i<1024;i++) {
00107     printf ("%5d ",hists[i]);
00108     if ((i & 0x0f)== 0x0f) printf ("\n");
00109   if ((i & 0xff) == 0xff) printf ("-----------------------------------------------\n");
00110     
00111   }
00112   printf ("===============================================\n");
00113 #endif  
00114 
00115   
00116 
00117   if ((mode & (HPNG_FILL_ZEROS | HPNG_LIN_INTERP)) | (rav>1)) { // spread between zeros - needed at high digital gains (near black with low gammas)
00118     for (j=0;j<4;j++)  if (colors_calc[colors] & (1<<j)) {
00119       lastmiddle_i=255;
00120       i=255;
00121       while ((hists[i+(j<<8)]==0) && (i>0)) i--;// skip high zeros
00122       while (i>0) {
00123        k=i;
00124        i--;
00125        while ((i>=0) && (hists[i+(j<<8)]==0)) i--;
00126        if ((k-i)>1) {
00127          a=hists[k+(j<<8)]/(k-i);
00128          for (l=k;l>i;l--) hists[l+(j<<8)] = a;
00129        }
00130        if ((mode & HPNG_LIN_INTERP) | (rav>1)) { //linear interpolation - also for high digital gains (near black with low gammas)
00131          newmiddle_i= (k+i+1)/2;
00132          for (l=lastmiddle_i-1;l>newmiddle_i;l--) { 
00133             hists[l+(j<<8)]= hists[newmiddle_i+(j<<8)] + ((l-newmiddle_i)* (hists[lastmiddle_i+(j<<8)]-hists[newmiddle_i+(j<<8)]))/(lastmiddle_i-newmiddle_i);
00134          }   
00135          lastmiddle_i=newmiddle_i;
00136        
00137        }
00138       }
00139 // apply running average (if any)
00140       if (rav>0) {
00141         k=0;
00142         l=0;
00143         for (i=0;i<256;i++) {
00144          rava[i]=hists[i+(j<<8)];
00145          k+=rava[i];
00146          if ((i-rav)>=0) k-=rava[i-rav];
00147          else l++;
00148          hists[i+(j<<8)]=k/l;
00149         }
00150       } 
00151       
00152       
00153     }
00154   }
00155 // calculate white if needed
00156   if (colors & 0x10) for (i=0;i<256;i++) hists[i+1024]=(hists[i]+hists[i+256]+hists[i+512]+hists[i+768])>>2;
00157 // calculate green if needed
00158   if (colors & 0x20) for (i=0;i<256;i++) hists[i+1280]=(hists[i+256]+hists[i+512])>>1;
00159   
00160   if (mode & HPNG_RUN_SQRT) {
00161     dcoeff=sqrt((32768.0*png_height)/coeff);
00162     for (j=0;j<6;j++) if (colors & (1 << j)) for (i=0;i<256;i++) hists[i+(j<<8)]=sqrt(hists[i+(j<<8)])*dcoeff;
00163   }
00164 // now scale data
00165   for (j=0;j<6;j++) if (colors & (1 << j)) for (i=0;i<256;i++) {
00166    hists[i+(j<<8)]=(hists[i+(j<<8)]*coeff) >> 16;
00167    if (hists[i+(j<<8)] > (png_height-1)) hists[i+(j<<8)] = png_height-1;
00168   }   
00169 
00170 #ifdef PNGHISTDEBUG
00171   printf ("w=%d, h=%d\n",ww,wh);
00172   for (i=0;i<1536;i++) {
00173     printf ("%5d ",hists[i]);
00174     if ((i & 0x0f)== 0x0f) printf ("\n");
00175   }
00176 #endif  
00177 //      sq = state.width * state.height;
00178 
00179   write_png("/var/html/hist.png", png_height, hists, mode, colors);
00180   
00181   return 0;
00182 }
00183 #define ERROR -1
00184 #define OK 0
00185 //#define HPNG_PLOT_BARS    1
00186 //#define HPNG_CONNECT_DOTS 2
00187 
00188 
00189 int write_png(char *file_name, int png_height, int data[1536], int mode, int colors)
00190 {
00191    FILE *fp;
00192    png_structp png_ptr;
00193    png_infop info_ptr;
00194 //   const char clrs[]={1,2,2,4,15,2}; // dim white
00195    const char clrs[]={1,2,2,4,7,2}; // bright white
00196 //   png_colorp palette;
00197    unsigned char cpalette[]= {0,   0,   0,
00198                         0xff,0,   0,
00199                         0,   0xff,0,
00200                         0xff,0xff,0,
00201                         0,   0,   0xff,
00202                         0xff,0,   0xff,
00203                         0,   0xff,0xff,
00204                         0xff,0xff,0xff,
00205                         0,   0,   0,
00206                         0x80,0,   0,
00207                         0,   0x80,0,
00208                         0x80,0x80,0,
00209                         0,   0,   0x80,
00210                         0x80,0,   0x80,
00211                         0,   0x80,0x80,
00212                         0x80,0x80,0x80};
00213   unsigned char ctransparency[]={0,  255,255,255,255,255,255,255,
00214                                  255,255,255,255,255,255,255,255};
00215   png_bytep   trans =   (png_bytep) ctransparency;
00216   
00217   png_colorp  palette = (png_colorp ) cpalette;
00218 //   palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
00219 //             * png_sizeof (png_color));
00220    png_uint_32 k;
00221    png_uint_32 height=png_height;
00222    png_uint_32 width=256;
00223    png_uint_32 bytes_per_pixel=1;
00224    png_byte image[256][256];
00225    png_bytep row_pointers[256];
00226    int i,j,c0,c,d,l,last;
00227    if (height>256) height=256;
00228    
00229    memset(image, 0, sizeof(image));
00230    for (j=0;j<6;j++) if (colors & (1 << j)){
00231      c0= clrs[j];
00232      last=png_height-1;
00233      for (i=0;i<256;i++) {
00234        c=c0 << ((i&1)?0:4);
00235        d=png_height-1-data[i+(j<<8)];
00236        if (d<=0) d=0;
00237        if (d>=png_height) d=png_height-1;
00238        image[d][i>>1] |= c;
00239        if (mode & 1){
00240 //         l=d-mode;
00241 //         if ((i&0x10)==0) l-=mode;
00242 //         l-= (i & 0xf);
00243 //         if (l<0) l=0;
00244          for (l=d+1; l<png_height; l++)image[l][i>>1] |= c;
00245 //         for (l=png_height; l>d; l--)image[l][i] |= c;
00246        } else if (mode & 2) {
00247          for (l=d+1; l<last; l++) image[l][i>>1] |= c; // only one of "for " can fire
00248          for (l=d-1; l>last; l--) image[l][i>>1] |= c; 
00249          last=d;
00250        
00251        }
00252        
00253      }
00254    }
00255    
00256    /* open the file */
00257    fp = fopen(file_name, "wb");
00258    if (fp == NULL)
00259       return (ERROR);
00260 
00261    /* Create and initialize the png_struct with the desired error handler
00262     * functions.  If you want to use the default stderr and longjump method,
00263     * you can supply NULL for the last three parameters.  We also check that
00264     * the library version is compatible with the one used at compile time,
00265     * in case we are using dynamically linked libraries.  REQUIRED.
00266     */
00267    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00268       NULL,NULL,NULL);
00269 
00270    if (png_ptr == NULL)
00271    {
00272       fclose(fp);
00273       return (ERROR);
00274    }
00275 
00276    /* Allocate/initialize the image information data.  REQUIRED */
00277    info_ptr = png_create_info_struct(png_ptr);
00278    if (info_ptr == NULL)
00279    {
00280       fclose(fp);
00281       png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
00282       return (ERROR);
00283    }
00284 
00285    /* Set error handling.  REQUIRED if you aren't supplying your own
00286     * error handling functions in the png_create_write_struct() call.
00287     */
00288    if (setjmp(png_jmpbuf(png_ptr)))
00289    {
00290       /* If we get here, we had a problem reading the file */
00291       fclose(fp);
00292       png_destroy_write_struct(&png_ptr, &info_ptr);
00293       return (ERROR);
00294    }
00295 
00296    /* One of the following I/O initialization functions is REQUIRED */
00297 //#ifdef streams /* I/O initialization method 1 */
00298    /* set up the output control if you are using standard C streams */
00299    png_init_io(png_ptr, fp);
00300 //#else  no_streams /* I/O initialization method 2 */
00301    /* If you are using replacement read functions, instead of calling
00302     * png_init_io() here you would call */
00303 //   png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
00304 //      user_IO_flush_function);
00305    /* where user_io_ptr is a structure you want available to the callbacks */
00306 //#endif// no_streams /* only use one initialization method */
00307 
00308    /* This is the hard way */
00309 
00310    /* Set the image information here.  Width and height are up to 2^31,
00311     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
00312     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
00313     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
00314     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
00315     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
00316     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
00317     */
00318    png_set_IHDR(png_ptr,
00319                 info_ptr,
00320                 256, // width
00321                 png_height, // height
00322                 4,          // bit_depth,
00323                 PNG_COLOR_TYPE_PALETTE, //PNG_COLOR_TYPE_???,
00324                 PNG_INTERLACE_NONE, //PNG_INTERLACE_????,
00325                 PNG_COMPRESSION_TYPE_BASE,
00326                 PNG_FILTER_TYPE_BASE);
00327 
00328    /* set the palette if there is one.  REQUIRED for indexed-color images */
00329 //   palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
00330 //             * png_sizeof (png_color));
00331    /* ... set palette colors ... */
00332    png_set_PLTE(png_ptr,
00333                 info_ptr,
00334                 palette,
00335                 PNG_MAX_PALETTE_LENGTH);
00336    png_set_tRNS(png_ptr,
00337                 info_ptr,
00338                 trans,
00339                 sizeof(trans), //16,
00340                 NULL); //, png_color_16p trans_values)                
00341    /* You must not free palette here, because png_set_PLTE only makes a link to
00342       the palette that you malloced.  Wait until you are about to destroy
00343       the png structure. */
00344 
00345    /* optional significant bit chunk */
00346    /* if we are dealing with a grayscale image then */
00347 #if 0   
00348    sig_bit.gray = 1; //true_bit_depth;
00349    /* otherwise, if we are dealing with a color image then */
00350    sig_bit.red = 1; //true_red_bit_depth;
00351    sig_bit.green = 1; //true_green_bit_depth;
00352    sig_bit.blue = 1; //true_blue_bit_depth;
00353    /* if the image has an alpha channel then */
00354    sig_bit.alpha = 1; //true_alpha_bit_depth;
00355    png_set_sBIT(png_ptr, info_ptr, sig_bit);
00356 #endif
00357 
00358    /* Optional gamma chunk is strongly suggested if you have any guess
00359     * as to the correct gamma of the image.
00360     */
00361 //   png_set_gAMA(png_ptr, info_ptr, gamma);
00362 
00363    /* Optionally write comments into the image */
00364 #if 0  
00365    text_ptr[0].key = "Title";
00366    text_ptr[0].text = "Histogram";// "Mona Lisa";
00367    text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
00368    text_ptr[1].key = "Author";
00369    text_ptr[1].text = "Elphel"; //"Leonardo DaVinci";
00370    text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
00371    text_ptr[2].key = "Description";
00372    text_ptr[2].text = "color histograms for the camera image/video"; //"<long text>";
00373    text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
00374 #ifdef PNG_iTXt_SUPPORTED
00375    text_ptr[0].lang = NULL;
00376    text_ptr[1].lang = NULL;
00377    text_ptr[2].lang = NULL;
00378 #endif
00379    png_set_text(png_ptr, info_ptr, text_ptr, 3);
00380 #endif
00381 
00382    /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
00383    /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
00384     * on read and must be written in accordance with the sRGB profile */
00385 
00386    /* Write the file header information.  REQUIRED */
00387    png_write_info(png_ptr, info_ptr);
00388 
00389    /* If you want, you can write the info in two steps, in case you need to
00390     * write your private chunk ahead of PLTE:
00391     *
00392     *   png_write_info_before_PLTE(write_ptr, write_info_ptr);
00393     *   write_my_chunk();
00394     *   png_write_info(png_ptr, info_ptr);
00395     *
00396     * However, given the level of known- and unknown-chunk support in 1.1.0
00397     * and up, this should no longer be necessary.
00398     */
00399 
00400    /* Once we write out the header, the compression type on the text
00401     * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
00402     * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
00403     * at the end.
00404     */
00405 
00406    /* set up the transformations you want.  Note that these are
00407     * all optional.  Only call them if you want them.
00408     */
00409 
00410    /* invert monochrome pixels */
00411 //   png_set_invert_mono(png_ptr);
00412 
00413    /* Shift the pixels up to a legal bit depth and fill in
00414     * as appropriate to correctly scale the image.
00415     */
00416 //   png_set_shift(png_ptr, &sig_bit);
00417 
00418    /* pack pixels into bytes */
00419 //   png_set_packing(png_ptr);
00420 
00421    /* swap location of alpha bytes from ARGB to RGBA */
00422 //   png_set_swap_alpha(png_ptr);
00423 
00424    /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
00425     * RGB (4 channels -> 3 channels). The second parameter is not used.
00426     */
00427 //   png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
00428 
00429    /* flip BGR pixels to RGB */
00430 //   png_set_bgr(png_ptr);
00431 
00432    /* swap bytes of 16-bit files to most significant byte first */
00433 //   png_set_swap(png_ptr);
00434 
00435    /* swap bits of 1, 2, 4 bit packed pixel formats */
00436 //   png_set_packswap(png_ptr);
00437 
00438    /* turn on interlace handling if you are not using png_write_image() */
00439 #if 0   
00440    if (interlacing)
00441       number_passes = png_set_interlace_handling(png_ptr);
00442    else
00443       number_passes = 1;
00444 #endif   
00445 
00446    /* The easiest way to write the image (you may have a different memory
00447     * layout, however, so choose what fits your needs best).  You need to
00448     * use the first method if you aren't handling interlacing yourself.
00449     */
00450 //   png_uint_32 k, height, width;
00451 //   png_byte image[height][width*bytes_per_pixel];
00452 //   png_bytep row_pointers[height];
00453 
00454    if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
00455      png_error (png_ptr, "Image is too tall to process in memory");
00456 
00457    for (k = 0; k < height; k++)
00458      row_pointers[k] = (png_bytep) image + k*width*bytes_per_pixel;
00459 
00460    /* One of the following output methods is REQUIRED */
00461    png_write_image(png_ptr, row_pointers);
00462 
00463 
00464    /* You can write optional chunks like tEXt, zTXt, and tIME at the end
00465     * as well.  Shouldn't be necessary in 1.1.0 and up as all the public
00466     * chunks are supported and you can use png_set_unknown_chunks() to
00467     * register unknown chunks into the info structure to be written out.
00468     */
00469 
00470    /* It is REQUIRED to call this to finish writing the rest of the file */
00471    png_write_end(png_ptr, info_ptr);
00472 
00473    /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
00474       as recommended in versions 1.0.5m and earlier of this example; if
00475       libpng mallocs info_ptr->palette, libpng will free it).  If you
00476       allocated it with malloc() instead of png_malloc(), use free() instead
00477       of png_free(). */
00478 //   png_free(png_ptr, palette);
00479 //   palette=NULL;
00480 
00481    /* Similarly, if you png_malloced any data that you passed in with
00482       png_set_something(), such as a hist or trans array, free it here,
00483       when you can be sure that libpng is through with it. */
00484 //   png_free(png_ptr, trans);
00485 //   trans=NULL;
00486 
00487    /* clean up after the write, and free any memory allocated */
00488    png_destroy_write_struct(&png_ptr, &info_ptr);
00489 
00490    /* close the file */
00491    fclose(fp);
00492 
00493    /* that's it */
00494    return (OK);
00495 }

Generated on Thu Aug 7 16:18:59 2008 for elphel by  doxygen 1.5.1