/// <summary> /// Decomposition of the input Bitmap into three band FloatImage-s. /// </summary> /// <param name="bmp">Input image.</param> /// <param name="border">Burder size in pixels.</param> /// <param name="red">Output red component.</param> /// <param name="green">Output green component.</param> /// <param name="blue">Output blue component.</param> public static void BitmapBands(Bitmap bmp, int border, out FloatImage red, out FloatImage green, out FloatImage blue) { int wid = bmp.Width; int hei = bmp.Height; red = new FloatImage(wid, hei, border); green = new FloatImage(wid, hei, border); blue = new FloatImage(wid, hei, border); const float inv255 = 1.0f / 255.0f; unsafe { fixed(float *rd = red.data) fixed(float *gd = green.data) fixed(float *bd = blue.data) { float *lr = rd + red.origin; float *lg = gd + green.origin; float *lb = bd + blue.origin; int i, j; for (j = 0; j < hei; j++, lr += red.stride, lg += green.stride, lb += blue.stride) { float *pr = lr; float *pg = lg; float *pb = lb; for (i = 0; i < wid; i++) { Color c = bmp.GetPixel(i, j); * pr++ = c.R * inv255; * pg++ = c.G * inv255; * pb++ = c.B * inv255; } } } } if (border > 0) { red.ComputeBorder(); green.ComputeBorder(); blue.ComputeBorder(); } }
/// <summary> /// Decomposition of the input Bitmap into three band FloatImage-s. /// </summary> /// <param name="bmp">Input image.</param> /// <param name="border">Burder size in pixels.</param> /// <param name="red">Output red component.</param> /// <param name="green">Output green component.</param> /// <param name="blue">Output blue component.</param> public static void BitmapBands( Bitmap bmp, int border, out FloatImage red, out FloatImage green, out FloatImage blue ) { int wid = bmp.Width; int hei = bmp.Height; red = new FloatImage( wid, hei, border ); green = new FloatImage( wid, hei, border ); blue = new FloatImage( wid, hei, border ); const float inv255 = 1.0f / 255.0f; unsafe { fixed ( float *rd = red.data ) fixed ( float *gd = green.data ) fixed ( float *bd = blue.data ) { float *lr = rd + red.origin; float *lg = gd + green.origin; float *lb = bd + blue.origin; int i, j; for ( j = 0; j < hei; j++, lr += red.stride, lg += green.stride, lb += blue.stride ) { float* pr = lr; float* pg = lg; float* pb = lb; for ( i = 0; i < wid; i++ ) { Color c = bmp.GetPixel( i, j ); *pr++ = c.R * inv255; *pg++ = c.G * inv255; *pb++ = c.B * inv255; } } } } if ( border > 0 ) { red.ComputeBorder(); green.ComputeBorder(); blue.ComputeBorder(); } }
/** * Common save code. * * @param stream Opened output bit-stream. * @param im Floating-point raster image. */ public void commonSave(Stream stream, FloatImage im) { if (stream == null) { throw new FileNotFoundException(); } // write HDR header: int width = im.Width; int height = im.Height; // "#?RADIANCE ... 0x0a, 0x0a -Y <height> +X <width>" StringBuilder sb = new StringBuilder("#?RADIANCE\nFORMAT=32-bit_rle_rgbe\n\n-Y "); sb.Append(height).Append(" +X ").Append(width).Append('\n'); int x, y, i; foreach (char c in sb.ToString()) { stream.WriteByte((byte)c); } // write the bitmap: float[] pix = new float[3]; assertScanline(width); for (y = 0; y < height; y++) // encode one scanline { // read the scanline & convert it to RGBe format: for (x = i = 0; x < width; x++, i += 4) { im.GetPixel(x, y, pix); Arith.RGBToRGBe(scanline, i, pix[0], pix[1], pix[2]); } writeScanline(width, stream); } }
/// <summary> /// Mean Absolute Difference of two images. /// </summary> /// <param name="b">The other image.</param> /// <returns>Sum of absolute pixel differences divided by number of pixels.</returns> public float MAD( FloatImage b ) { if ( b.Width != Width || b.Height != Height ) return 2.0f; double sum = 0.0; unsafe { fixed ( float* ad = data ) fixed ( float* bd = b.data ) { float* la = ad + origin; float* lb = bd + b.origin; int i, j; for ( j = 0; j++ < height; la += stride, lb += b.stride ) { float* pa = la; float* pb = lb; for ( i = 0; i++ < width; ) sum += Math.Abs( *pa++ - *pb++ ); } } } return( (float)(sum / (width * height)) ); }
/** * Common load code. * * @param stream Opened input bit-stream. */ public FloatImage commonLoad(Stream stream) { if (stream == null) { throw new FileNotFoundException(); } // decode HDR file into raster image: // "#?RADIANCE ... 0x0a, 0x0a {+|-}Y <height> {+|-}X <width>" bool bottomUp = false; bool leftToRight = true; int width = 0; int height = 0; int last; int act = stream.ReadByte(); do { last = act; act = stream.ReadByte(); }while (act >= 0 && (last != 0x0a || act != 0x0a)); if (act < 0) { throw new IOException("Error in HDR header"); } string axis1 = readToken(stream); int dim1; int.TryParse(readToken(stream), out dim1); string axis2 = readToken(stream); int dim2; int.TryParse(readToken(stream), out dim2); if (axis1 == null || axis1.Length != 2 || axis1 == null || axis1.Length != 2) { throw new IOException("Error in HDR header"); } if (char.ToLower(axis1[1]) == 'x') { width = dim1; leftToRight = (axis1[0] == '+'); } else if (char.ToLower(axis1[1]) == 'y') { height = dim1; bottomUp = (axis1[0] == '+'); } else { throw new IOException("Error in HDR header"); } if (char.ToLower(axis2[1]) == 'x') { width = dim2; leftToRight = (axis2[0] == '+'); } else if (char.ToLower(axis2[1]) == 'y') { height = dim2; bottomUp = (axis2[0] == '+'); } else { throw new IOException("Error in HDR header"); } if (width <= 0 || height <= 0) { throw new IOException("Error in HDR header"); } // init memory bitmap .. FloatImage im = new FloatImage(width, height, 3); // .. and finally read the binary data into it: int x, y, dy, i; float[] pix = new float[3]; if (bottomUp) { y = height - 1; dy = -1; } else { y = 0; dy = 1; } while (y >= 0 && y < height) // read one scanline { readScanline(width, stream); // convert RGBe pixels into float[3] RGB: if (leftToRight) { for (x = i = 0; x < width; x++, i += 4) { Arith.RGBeToRGB(scanline, i, pix, 0); im.PutPixel(x, y, pix); } } else { for (x = width, i = 0; --x >= 0; i += 4) { Arith.RGBeToRGB(scanline, i, pix, 0); im.PutPixel(x, y, pix); } } y += dy; } return(im); }