public static Image Fold(Func <Colord, Colord, Colord> function, Colord color, IEnumerable <Image> images) { var size = images.Aggregate( new Size3i(int.MaxValue, int.MaxValue, int.MaxValue), (s, i) => Ibasa.Numerics.Geometry.Size.Min(s, i.Size)); var result = new Image(size); for (int z = 0; z < result.Depth; ++z) { for (int y = 0; y < result.Height; ++y) { for (int x = 0; x < result.Width; ++x) { var fold = color; foreach (var image in images) { fold = function(fold, image[x, y, z]); } result[x, y, z] = fold; } } } return(result); }
public override void GetBytes( Colord[] source, int index, int width, int height, System.IO.Stream destination, int rowPitch, int slicePitch, Boxi sourceBoxi, Point3i destinationPoint) { throw new NotImplementedException(); }
public void Map(Colord[] colors, int colorIndex, int x, int y, int z, int width, int height) { //find width and height Width = Functions.Min(4, width - x); Height = Functions.Min(4, height - y); //set points and weights to zero Array.Clear(Points, 0, Points.Length); Array.Clear(Weights, 0, Weights.Length); IsTransparent = false; int zindex = colorIndex + z * (height * width); for (int iy = 0; iy < Height; ++iy) { int xyindex = (x) + (y + iy) * width + zindex; for (int ix = 0; ix < Width; ++ix) { Colord pixel = colors[xyindex++]; Points[ix, iy] = new Vector3d(pixel.R, pixel.G, pixel.B); Weights[ix, iy] = WeightColourByAlpha ? pixel.A : 1.0; IsTransparent = pixel.A < 0.5 | IsTransparent; } } }
public Colord[] GetPixels(int x, int y, int z, int width, int height, int depth) { Contract.Requires(x < Width && x >= 0, "x must be zero or greater, and less than the image width."); Contract.Requires(y < Height && y >= 0, "y must be zero or greater, and less than the image height."); Contract.Requires(z < Depth && z >= 0, "z must be zero or greater, and less than the image depth."); Contract.Requires(width > 0, "width must be greater than zero."); Contract.Requires(height > 0, "height must be greater than zero."); Contract.Requires(depth > 0, "depth must be greater than zero."); Contract.Requires(x + width < Width, "x plus width is greater than image width."); Contract.Requires(y + height < Height, "y plus height is greater than image height."); Contract.Requires(z + depth < Depth, "z plus depth is greater than image depth."); Colord[] pixels = new Colord[width * height * depth]; for (int destZ = 0, srcZ = z; destZ < depth; ++destZ, ++srcZ) { int destZOffset = destZ * height; for (int destY = 0, srcY = y; destY < height; ++destY, ++srcY) { int destYOffset = destY * width + destZOffset; for (int destX = 0, srcX = x; destX < width; ++destX, ++srcX) { int destOffset = destX + destYOffset; pixels[destOffset] = GetPixel(srcX, srcY, srcZ); } } } return(pixels); }
public void SetPixel(int index, Colord pixel) { Contract.Requires(index >= 0, "index is less than zero."); Contract.Requires(index < Pixels.Length, "index is out of image bounds."); Pixels[index] = pixel; }
public void Map(Colord[] colors, int colorIndex, int x, int y, int z, int width, int height) { //find width and height Width = Functions.Min(4, width - x); Height = Functions.Min(4, height - y); //set points and weights to zero Array.Clear(Points, 0, Points.Length); Array.Clear(Weights, 0, Weights.Length); IsTransparent = false; int zindex = colorIndex + z * (height * width); for (int iy = 0; iy < Height; ++iy) { int xyindex = (x) + (y + iy) * width + zindex; for (int ix = 0; ix < Width; ++ix) { Colord pixel = colors[xyindex++]; Points[ix,iy] = new Vector3d(pixel.R, pixel.G, pixel.B); Weights[ix,iy] = WeightColourByAlpha ? pixel.A : 1.0; IsTransparent = pixel.A < 0.5 | IsTransparent; } } }
public void Clear(Colord color) { for (int i = 0; i < Pixels.Length; ++i) { Pixels[i] = color; } }
public void SetPixel(int x, int y, int z, Colord pixel) { Contract.Requires(x < Width && x >= 0, "x must be zero or greater, and less than the image width."); Contract.Requires(y < Height && y >= 0, "y must be zero or greater, and less than the image height."); Contract.Requires(z < Depth && z >= 0, "z must be zero or greater, and less than the image depth."); Pixels[x + y * Width + z * (Width * Height)] = pixel; }
static void Scale2DCubic(Image source, Image scaled) { double scaleX = (double)source.Width / scaled.Width; double scaleY = (double)source.Height / scaled.Height; for (int y = 0; y < scaled.Height; ++y) { int y1 = (int)(y * scaleY); int y2 = Functions.Min(y1 + 1, source.Height - 1); int y0 = Functions.Max(y1 - 1, 0); int y3 = Functions.Min(y2 + 1, source.Height - 1); double fY = (y * scaleY) - y1; double fY2 = fY * fY; double fY3 = fY2 * fY; for (int x = 0; x < scaled.Width; ++x) { int x1 = (int)(x * scaleX); int x2 = Functions.Min(x1 + 1, source.Width - 1); int x0 = Functions.Max(x1 - 1, 0); int x3 = Functions.Min(x2 + 1, source.Width - 1); double fX = (x * scaleX) - x1; double fX2 = fX * fX; double fX3 = fX2 * fX; Colord p = Cerp( Cerp( source.GetPixel(x0, y0, 0), source.GetPixel(x1, y0, 0), source.GetPixel(x2, y0, 0), source.GetPixel(x3, y0, 0), fX, fX2, fX3), Cerp( source.GetPixel(x0, y1, 0), source.GetPixel(x1, y1, 0), source.GetPixel(x2, y1, 0), source.GetPixel(x3, y1, 0), fX, fX2, fX3), Cerp( source.GetPixel(x0, y2, 0), source.GetPixel(x1, y2, 0), source.GetPixel(x2, y2, 0), source.GetPixel(x3, y2, 0), fX, fX2, fX3), Cerp( source.GetPixel(x0, y3, 0), source.GetPixel(x1, y3, 0), source.GetPixel(x2, y3, 0), source.GetPixel(x3, y3, 0), fX, fX2, fX3), fY, fY2, fY3); scaled.SetPixel(x, 0, 0, p); } } }
static Colord Cerp(Colord p0, Colord p1, Colord p2, Colord p3, double f, double f2, double f3) { Colord p = (p3 - p2) - (p0 - p1); Colord q = (p0 - p1) - p; Colord r = p2 - p0; Colord s = p1; return(p * f3 + q * f2 + r * f + s); }
static Colord Cerp(Colord p0, Colord p1, Colord p2, Colord p3, double f, double f2, double f3) { Colord p = (p3 - p2) - (p0 - p1); Colord q = (p0 - p1) - p; Colord r = p2 - p0; Colord s = p1; return p*f3 + q*f2 + r*f + s; }
public static Image Normalmap(Image depthmap, float depth) { //Create normalmap, only use the first slice if a 3D texture Image normalmap = new Image(new Size3i(depthmap.Width, depthmap.Height, 1)); for (int y = 0; y < normalmap.Height; ++y) { for (int x = 0; x < normalmap.Width; ++x) { double dx = 0.0; double dy = 0.0; double p; p = depthmap[x - 1, y - 1].R * depth; dx -= p; dy -= p; p = depthmap[x, y - 1].R * depth; dy -= 2 * p; p = depthmap[x + 1, y - 1].R * depth; dx += p; dy -= p; p = depthmap[x - 1, y].R * depth; dx -= 2 * p; p = depthmap[x + 1, y].R * depth; dx += 2 * p; p = depthmap[x - 1, y + 1].R * depth; dx -= p; dy += p; p = depthmap[x, y + 1].R * depth; dy += 2 * p; p = depthmap[x + 1, y + 1].R * depth; dx += p; dy += p; Vector3d n = Vector.Normalize(new Vector3d(dx, dy, 0.0)); //[-1,1] -> [0,1] n = (n * 0.5) + Vector3d.One; normalmap[x, y] = new Colord(n.X, n.Y, n.Z); } } return(normalmap); }
public Image(Image source) { Contract.Requires(source != null); Size = source.Size; Pixels = new Colord[source.Pixels.Length]; Array.Copy(source.Pixels, Pixels, Pixels.Length); AddressX = source.AddressX; AddressY = source.AddressY; AddressZ = source.AddressZ; }
public Image(Size3i size) { Contract.Requires(size.Width > 0); Contract.Requires(size.Height > 0); Contract.Requires(size.Depth > 0); Size = size; Pixels = new Colord[Width * Height * Depth]; AddressX = AddressMode.Clamp; AddressY = AddressMode.Clamp; AddressZ = AddressMode.Clamp; }
public Image(Colord[] pixels) { Contract.Requires(pixels != null); Size = new Size3i(pixels.GetLength(0), 1, 1); Pixels = new Colord[Width]; for (int x = 0; x < Width; ++x) { this[x] = pixels[x]; } AddressX = AddressMode.Clamp; AddressY = AddressMode.Clamp; AddressZ = AddressMode.Clamp; }
public ChannelSet(Colord[] pixels, int mask, int channel) { Count = 0; Points = new double[16]; // create the minimal set for( int i = 0; i < 16; ++i ) { // check this pixel is enabled int bit = 1 << i; if( ( mask & (1 << i) ) == 0 ) { remap[i] = -1; continue; } // loop over previous points for a match for( int j = 0;; ++j ) { // allocate a new point if( j == i ) { // add the point Points[Count] = pixels[i][channel]; remap[i] = Count; // advance ++Count; break; } // check for a match int oldbit = 1 << j; bool match = ( ( mask & oldbit ) != 0 ) && ( pixels[i][channel] == pixels[j][channel]); if( match ) { // get the index of the match int index = remap[j]; // map to this point remap[i] = index; break; } } } }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { //seek to start source.Seek( sourceBoxi.X * 4 + sourceBoxi.Y * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; ++y) { int xyindex = destinationPoint.X + (destinationPoint.Y + y) * width + zindex; //write scan line for (int x = 0; x < sourceBoxi.Width; ++x) { int r = source.ReadByte(); int g = source.ReadByte(); int b = source.ReadByte(); int a = source.ReadByte(); if ((r | g | b | a) < 0) { throw new System.IO.EndOfStreamException(); } destination[xyindex++] = new Colord( (sbyte)(byte)r / sbyte.MaxValue, (sbyte)(byte)g / sbyte.MaxValue, (sbyte)(byte)b / sbyte.MaxValue, (sbyte)(byte)a / sbyte.MaxValue); } //seek to next scan line source.Seek(rowPitch - sourceBoxi.Width * 4, System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - sourceBoxi.Height * rowPitch, System.IO.SeekOrigin.Current); } }
public Image(Colord[,] pixels) { Contract.Requires(pixels != null); Size = new Size3i(pixels.GetLength(0), pixels.GetLength(1), 1); Pixels = new Colord[Width * Height]; for (int y = 0; y < Height; ++y) { for (int x = 0; x < Width; ++x) { this[x, y] = pixels[x, y]; } } AddressX = AddressMode.Clamp; AddressY = AddressMode.Clamp; AddressZ = AddressMode.Clamp; }
public Image(Resource source, int mipSlice, int arraySlice) { Contract.Requires(source != null); Contract.Requires(0 < mipSlice); Contract.Requires(mipSlice < source.MipLevels); Contract.Requires(0 < arraySlice); Contract.Requires(arraySlice < source.ArraySize); Size = source.ComputeMipSliceSize(mipSlice); Pixels = new Colord[Width * Height * Depth]; source.GetColords( mipSlice, arraySlice, Pixels, 0, Size.Width, Size.Height, new Boxi(Point3i.Zero, Size), Point3i.Zero); AddressX = AddressMode.Clamp; AddressY = AddressMode.Clamp; AddressZ = AddressMode.Clamp; }
//public static Image Convolution(Image image, Matrix kernel) //{ // if (image == null) // throw new ArgumentNullException("image"); // if (kernel == null) // throw new ArgumentNullException("kernel"); // Image result = new Image(image.Size); // for (int y = 0; y < image.Height; ++y) // { // for (int x = 0; x < image.Width; ++x) // { // Colord p = new Colord(); // for (int j = 0; j < kernel.Rows.Count; ++j) // { // for (int i = 0; i < kernel.Columns.Count; ++i) // { // p += image[x - i, y - j] * kernel[i, j]; // } // } // result[x, y] = p; // } // } // return result; //} #endregion #region Dither public static void Dither(Image image, Func <Colord, Colord> quantize) { for (int z = 0; z < image.Depth; ++z) { for (int y = 0; y < image.Height; ++y) { for (int x = 0; x < image.Width; ++x) { Colord oldc = image[x, y, z]; Colord newc = quantize(oldc); image[x, y, z] = newc; Colord error = oldc - newc; image[x + 1, y, z] += (7.0 / 16.0 * error); image[x - 1, y + 1, z] += (3.0 / 16.0 * error); image[x, y + 1, z] += (5.0 / 16.0 * error); image[x + 1, y + 1, z] += (1.0 / 16.0 * error); } } } }
public override void GetColords( Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { //seek to start source.Seek( sourceBoxi.X * 12 + sourceBoxi.Y * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); var buffer = new byte[12]; for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; ++y) { int xyindex = destinationPoint.X + (destinationPoint.Y + y) * width + zindex; //write scan line for (int x = 0; x < sourceBoxi.Width; ++x) { Ibasa.IO.StreamExtensions.ReadBytes(source, buffer, 0, 12); float r = BitConverter.ToSingle(buffer, 0); float g = BitConverter.ToSingle(buffer, 4); float b = BitConverter.ToSingle(buffer, 8); destination[xyindex++] = new Colord(r, g, b, 0); } //seek to next scan line source.Seek(rowPitch - sourceBoxi.Width * 12, System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - sourceBoxi.Height * rowPitch, System.IO.SeekOrigin.Current); } }
static Colord Serp(Colord p0, Colord p1, Colord p2, Colord p3, double cint0, double cint1, double cint2, double cint3) { return p0 * cint0 + p1 * cint1 + p2 * cint2 + p3 * cint3; }
public Image(Colord[,,] pixels) { Contract.Requires(pixels != null); Size = new Size3i(pixels.GetLength(0), pixels.GetLength(1), pixels.GetLength(2)); Pixels = new Colord[Width * Height * Depth]; for (int z = 0; z < Depth; ++z) { for (int y = 0; y < Height; ++y) { for (int x = 0; x < Width; ++x) { this[x, y, z] = pixels[x, y, z]; } } } AddressX = AddressMode.Clamp; AddressY = AddressMode.Clamp; AddressZ = AddressMode.Clamp; }
static Colord Lerp(Colord p0, Colord p1, double f) { return p0 + f * (p1 - p0); }
public static Image Normalmap(Image depthmap, float depth) { //Create normalmap, only use the first slice if a 3D texture Image normalmap = new Image(new Size3i(depthmap.Width, depthmap.Height, 1)); for (int y = 0; y < normalmap.Height; ++y) { for (int x = 0; x < normalmap.Width; ++x) { double dx = 0.0; double dy = 0.0; double p; p = depthmap[x - 1, y - 1].R * depth; dx -= p; dy -= p; p = depthmap[x, y - 1].R * depth; dy -= 2 * p; p = depthmap[x + 1, y - 1].R * depth; dx += p; dy -= p; p = depthmap[x - 1, y].R * depth; dx -= 2 * p; p = depthmap[x + 1, y].R * depth; dx += 2 * p; p = depthmap[x - 1, y + 1].R * depth; dx -= p; dy += p; p = depthmap[x, y + 1].R * depth; dy += 2 * p; p = depthmap[x + 1, y + 1].R * depth; dx += p; dy += p; Vector3d n = Vector.Normalize(new Vector3d(dx, dy, 0.0)); //[-1,1] -> [0,1] n = (n * 0.5) + Vector3d.One; normalmap[x, y] = new Colord(n.X, n.Y, n.Z); } } return normalmap; }
public static Image Fold(Func<Colord, Colord, Colord> function, Colord color, IEnumerable<Image> images) { var size = images.Aggregate( new Size3i(int.MaxValue, int.MaxValue, int.MaxValue), (s, i) => Ibasa.Numerics.Geometry.Size.Min(s, i.Size)); var result = new Image(size); for (int z = 0; z < result.Depth; ++z) { for (int y = 0; y < result.Height; ++y) { for (int x = 0; x < result.Width; ++x) { var fold = color; foreach (var image in images) { fold = function(fold, image[x,y,z]); } result[x, y, z] = fold; } } } return result; }
private void DecodeMode7(byte[] block, Colord[] pixels) { }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); Colord[] codes = new Colord[4]; byte[] block = new byte[BlockSize]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) throw new System.IO.EndOfStreamException(); read += bytes; } // decompress the block int color0 = BitConverter.ToUInt16(block, 0); int color1 = BitConverter.ToUInt16(block, 2); uint indices = BitConverter.ToUInt32(block, 4); // unpack the endpoints codes[0] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color0)); codes[1] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color1)); // generate the midpoints if (color0 > color1) { codes[2] = Numerics.Color.Lerp(codes[0], codes[1], 1.0 / 3.0); codes[3] = Numerics.Color.Lerp(codes[0], codes[1], 2.0 / 3.0); } else { codes[2] = Numerics.Color.Lerp(codes[0], codes[1], 1.0 / 2.0); codes[3] = new Numerics.Colord(0.0, 0.0, 0.0, 0.0); } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; for (int x2 = 0; x2 < bwidth; ++x2) { uint codeIndex = (indices >> ((x2 + (y2 * 4)) << 1) & 3); destination[xyindex++] = codes[codeIndex]; } } } //seek to next scan line source.Seek(rowPitch - (((sourceBoxi.Width + 3) / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - (((sourceBoxi.Height + 3) / 4) * ((sourceBoxi.Width + 3) / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public void SetPixels(int x, int y, int z, int width, int height, int depth, Colord[] pixels) { Contract.Requires(width * height * depth == pixels.Length, "pixels length does not match length given by width, height and depth."); Contract.Requires(x < Width && x >= 0, "x must be zero or greater, and less than the image width."); Contract.Requires(y < Height && y >= 0, "y must be zero or greater, and less than the image height."); Contract.Requires(z < Depth && z >= 0, "z must be zero or greater, and less than the image depth."); Contract.Requires(width > 0, "width must be greater than zero."); Contract.Requires(height > 0, "height must be greater than zero."); Contract.Requires(depth > 0, "depth must be greater than zero."); Contract.Requires(x + width < Width, "x plus width is greater than image width."); Contract.Requires(y + height < Height, "y plus height is greater than image height."); Contract.Requires(z + depth < Depth, "z plus depth is greater than image depth."); for (int destZ = z, srcZ = 0; srcZ < depth; ++destZ, ++srcZ) { int srcZOffset = srcZ * height; for (int destY = y, srcY = 0; srcY < height; ++destY, ++srcY) { int srcYOffset = srcY * width + srcZOffset; for (int destX = x, srcX = 0; srcX < width; ++destX, ++srcX) { int srcOffset = srcX + srcYOffset; SetPixel(destX, destY, destZ, pixels[srcOffset]); } } } }
static void Scale2DSpline(Image source, Image scaled) { double scaleX = (double)source.Width / scaled.Width; double scaleY = (double)source.Height / scaled.Height; for (int y = 0; y < scaled.Height; ++y) { int y1 = (int)(y * scaleY); int y2 = Functions.Min(y1 + 1, source.Height - 1); int y0 = Functions.Max(y1 - 1, 0); int y3 = Functions.Min(y2 + 1, source.Height - 1); double fY = (y * scaleY) - y1; double cinty0 = (-fY * (fY - 1) * (fY - 2)) / 6; double cinty1 = (3 * (fY + 1) * (fY - 1) * (fY - 2)) / 6; double cinty2 = (-3 * (fY + 1) * fY * (fY - 2)) / 6; double cinty3 = ((fY + 1) * fY * (fY - 1)) / 6; for (int x = 0; x < scaled.Width; ++x) { int x1 = (int)(x * scaleX); int x2 = Functions.Min(x1 + 1, source.Width - 1); int x0 = Functions.Max(x1 - 1, 0); int x3 = Functions.Min(x2 + 1, source.Width - 1); double fX = (x * scaleX) - x1; double cintx0 = (-fX * (fX - 1) * (fX - 2)) / 6; double cintx1 = (3 * (fX + 1) * (fX - 1) * (fX - 2)) / 6; double cintx2 = (-3 * (fX + 1) * fX * (fX - 2)) / 6; double cintx3 = ((fX + 1) * fX * (fX - 1)) / 6; Colord p = Serp( Serp( source.GetPixel(x0, y0, 0), source.GetPixel(x1, y0, 0), source.GetPixel(x2, y0, 0), source.GetPixel(x3, y0, 0), cintx0, cintx1, cintx2, cintx3), Serp( source.GetPixel(x0, y1, 0), source.GetPixel(x1, y1, 0), source.GetPixel(x2, y1, 0), source.GetPixel(x3, y1, 0), cintx0, cintx1, cintx2, cintx3), Serp( source.GetPixel(x0, y2, 0), source.GetPixel(x1, y2, 0), source.GetPixel(x2, y2, 0), source.GetPixel(x3, y2, 0), cintx0, cintx1, cintx2, cintx3), Serp( source.GetPixel(x0, y3, 0), source.GetPixel(x1, y3, 0), source.GetPixel(x2, y3, 0), source.GetPixel(x3, y3, 0), cintx0, cintx1, cintx2, cintx3), cinty0, cinty1, cinty2, cinty3); scaled.SetPixel(x, y, 0, p); } } }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) { throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); } //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); Colord[] ccodes = new Colord[4]; double[] acodes = new double[8]; byte[] block = new byte[BlockSize]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) { throw new System.IO.EndOfStreamException(); } read += bytes; } // decompress the block int alpha0 = block[0]; int alpha1 = block[1]; ulong aindices = BitConverter.ToUInt16(block, 2) | ((ulong)BitConverter.ToUInt32(block, 4) << 16); //Only 6 bytes int color0 = BitConverter.ToUInt16(block, 8); int color1 = BitConverter.ToUInt16(block, 10); uint cindices = BitConverter.ToUInt32(block, 12); // unpack the endpoints ccodes[0] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color0)); ccodes[1] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color1)); // generate the midpoints ccodes[2] = Numerics.Color.Lerp(ccodes[0], ccodes[1], 1.0 / 3.0); ccodes[3] = Numerics.Color.Lerp(ccodes[0], ccodes[1], 2.0 / 3.0); //unpack alpha acodes[0] = alpha0 / 255.0; acodes[1] = alpha1 / 255.0; //generate midpoints if (alpha0 > alpha1) { acodes[2] = (6 * acodes[0] + 1 * acodes[1]) / 7.0; // bit code 010 acodes[3] = (5 * acodes[0] + 2 * acodes[1]) / 7.0; // bit code 011 acodes[4] = (4 * acodes[0] + 3 * acodes[1]) / 7.0; // bit code 100 acodes[5] = (3 * acodes[0] + 4 * acodes[1]) / 7.0; // bit code 101 acodes[6] = (2 * acodes[0] + 5 * acodes[1]) / 7.0; // bit code 110 acodes[7] = (1 * acodes[0] + 6 * acodes[1]) / 7.0; // bit code 111 } else { acodes[2] = (4 * acodes[0] + 1 * acodes[1]) / 5.0; // bit code 010 acodes[3] = (3 * acodes[0] + 2 * acodes[1]) / 5.0; // bit code 011 acodes[4] = (2 * acodes[0] + 3 * acodes[1]) / 5.0; // bit code 100 acodes[5] = (1 * acodes[0] + 4 * acodes[1]) / 5.0; // bit code 101 acodes[6] = 0.0; // bit code 110 acodes[7] = 1.0; // bit code 111 } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; for (int x2 = 0; x2 < bwidth; ++x2) { uint codeIndex = (cindices >> ((x2 + (y2 * 4)) << 1) & 3); ulong alphaIndex = (aindices >> ((x2 + (y2 * 4)) << 2)) & 7; destination[xyindex++] = new Numerics.Colord( ccodes[codeIndex].R, ccodes[codeIndex].G, ccodes[codeIndex].B, acodes[alphaIndex]); } } } //seek to next scan line source.Seek(rowPitch - ((sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - ((sourceBoxi.Height / 4) * (sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); byte[] block = new byte[BlockSize]; Colord[] pixels = new Colord[16]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) throw new System.IO.EndOfStreamException(); read += bytes; } int mode = (block[0] & (-block[0])); switch (mode) { case 1: DecodeMode0(block, pixels); break; case 2: DecodeMode1(block, pixels); break; case 4: DecodeMode2(block, pixels); break; case 8: DecodeMode3(block, pixels); break; case 16: DecodeMode4(block, pixels); break; case 32: DecodeMode5(block, pixels); break; case 64: DecodeMode6(block, pixels); break; case 128: DecodeMode7(block, pixels); break; } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; int xy2index = y2 * 4; for (int x2 = 0; x2 < bwidth; ++x2) { destination[xyindex++] = pixels[xy2index++]; } } } //seek to next scan line source.Seek(rowPitch - ((sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - ((sourceBoxi.Height / 4) * (sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public static bool ThresholdBoundary(Colord value) { return (value.R >= 0.5); }
private unsafe void DecodeMode0(byte[] block, Colord[] pixels) { //Number of subsets in each partition: 3 //Partition bits: 4 //Rotation bits: 0 //Index selection bits: 0 //Colord bits: 4 //Alpha bits: 0 //Endpoint P-bits: 1 //Shared P-bits: 0 //Index bits per element: 3 //Secondary index bits per element: 0 // [76543210] counter // [rrrppppm] 0 // [rrrrrrrr] 1 // [rrrrrrrr] 2 // [gggrrrrr] 3 // [gggggggg] 4 // [gggggggg] 5 // [bbbggggg] 6 // [bbbbbbbb] 7 // [bbbbbbbb] 8 // [pppbbbbb] 9 // [xxxxxppp] A // [xxxxxxxx] B // [xxxxxxxx] C // [xxxxxxxx] D // [xxxxxxxx] E // [xxxxxxxx] F int partition = (block[0] >> 1) & 0x0F; int* codes = stackalloc int[18]; codes[0] = ((block[0] >> 1) | (block[1] << 7)) & 0xF0 | ((block[9] >> 2) & 0x08); codes[1] = ((block[3] >> 1) | (block[4] << 7)) & 0xF0 | ((block[9] >> 2) & 0x08); codes[2] = ((block[6] >> 1) | (block[7] << 7)) & 0xF0 | ((block[9] >> 2) & 0x08); codes[3] = (block[1] << 3) & 0xF0 | ((block[9] >> 3) & 0x08); codes[4] = (block[4] << 3) & 0xF0 | ((block[9] >> 3) & 0x08); codes[5] = (block[7] << 3) & 0xF0 | ((block[9] >> 3) & 0x08); codes[6] = ((block[1] >> 1) | (block[2] << 7)) & 0xF0 | ((block[9] >> 4) & 0x08); codes[7] = ((block[4] >> 1) | (block[5] << 7)) & 0xF0 | ((block[9] >> 4) & 0x08); codes[8] = ((block[7] >> 1) | (block[8] << 7)) & 0xF0 | ((block[9] >> 4) & 0x08); codes[9] = (block[2] << 3) & 0xF0 | ((block[10] << 3) & 0x08); codes[10] = (block[5] << 3) & 0xF0 | ((block[10] << 3) & 0x08); codes[11] = (block[8] << 3) & 0xF0 | ((block[10] << 3) & 0x08); codes[12] = ((block[2] >> 1) | (block[3] << 7)) & 0xF0 | ((block[10] << 2) & 0x08); codes[13] = ((block[5] >> 1) | (block[6] << 7)) & 0xF0 | ((block[10] << 2) & 0x08); codes[14] = ((block[8] >> 1) | (block[9] << 7)) & 0xF0 | ((block[10] << 2) & 0x08); codes[15] = (block[3] << 3) & 0xF0 | ((block[10] << 1) & 0x08); codes[16] = (block[6] << 3) & 0xF0 | ((block[10] << 1) & 0x08); codes[17] = (block[9] << 3) & 0xF0 | ((block[10] << 1) & 0x08); codes[0] |= (codes[0] >> 5); codes[1] |= (codes[1] >> 5); codes[2] |= (codes[2] >> 5); codes[3] |= (codes[3] >> 5); codes[4] |= (codes[4] >> 5); codes[5] |= (codes[5] >> 5); codes[6] |= (codes[6] >> 5); codes[7] |= (codes[7] >> 5); codes[8] |= (codes[8] >> 5); codes[9] |= (codes[9] >> 5); codes[10] |= (codes[10] >> 5); codes[11] |= (codes[11] >> 5); codes[12] |= (codes[12] >> 5); codes[13] |= (codes[13] >> 5); codes[14] |= (codes[14] >> 5); codes[15] |= (codes[15] >> 5); codes[16] |= (codes[16] >> 5); codes[17] |= (codes[17] >> 5); for (int i = 0; i < 16; ++i) { int colorIndex = 0; //64 <= partition < 64 + 16 //if (i == 0) // colorIndex = (block.z >> 19) & 0x03; //else if (i < candidateFixUpIndex1DOrdered[partition][0]) //{ // if (i < 4) // colorIndex = (block.z >> (i * 3 + 18)) & 0x07; // else if (i == 4) // colorIndex = ((block.z >> (i * 3 + 18)) & 0x03) | ((block.w << 2) & 0x04); // else // colorIndex = (block.w >> (i * 3 - 14)) & 0x07; //} //else if (i == candidateFixUpIndex1DOrdered[partition][0]) //{ // if (i <= 4) // colorIndex = (block.z >> (i * 3 + 18)) & 0x03; // else // colorIndex = (block.w >> (i * 3 - 14)) & 0x03; //} //else if (i < candidateFixUpIndex1DOrdered[partition][1]) //{ // if (i <= 4) // colorIndex = (block.z >> (i * 3 + 17)) & 0x07; // else // colorIndex = (block.w >> (i * 3 - 15)) & 0x07; //} //else if (i == candidateFixUpIndex1DOrdered[partition][1]) //i >= 8 // colorIndex = (block.w >> (i * 3 - 15)) & 0x03; //else //i >= 9 // colorIndex = (block.w >> (i * 3 - 16)) & 0x07; //int subsetIndex = (candidateSectionCompressed[partition] >> (30 - i * 2)) & 0x03; int subsetIndex = 0; pixels[i] = InterpolateColord(Weights3[colorIndex], codes, subsetIndex); } }
public static Image DistanceTransform( Image source, int width, int height, int depth, Func<Colord, bool> boundary, Metric metric) { Image dt = new Image(new Size3i(width, height, depth)); double zScale = depth == 1 ? 0 : (double)(source.Depth-1)/(depth-1); double yScale = height == 1 ? 0 : (double)(source.Height-1)/(height-1); double xScale = width == 1 ? 0 : (double)(source.Width-1)/(width-1); int spread = (int)Functions.Max(source.Width, Functions.Max(source.Height, Functions.Max(source.Depth, 3))); if (spread % 2 == 0) //0 % 2 == 0 spread += 1; //spread must be odd and at least 3 for (int z = 0; z < dt.Depth; ++z) { int srcZ = (int)(z * zScale); for (int y = 0; y < dt.Height; ++y) { int srcY = (int)(y * yScale); for (int x = 0; x < dt.Width; ++x) { int srcX = (int)(x * xScale); int boxSize = 3; double minDistance = double.MaxValue; bool srcBoundary = boundary(source[srcX, srcY, srcZ]); while (boxSize <= spread) { int minZ = srcZ - (boxSize/2); int maxZ = srcZ + (boxSize/2); int minY = srcY - (boxSize/2); int maxY = srcY + (boxSize/2); int minX = srcX - (boxSize/2); int maxX = srcX + (boxSize/2); int zStart = Functions.Max(minZ, 0); int zEnd = Functions.Min(maxZ+1, source.Depth); int yStart = Functions.Max(minY, 0); int yEnd = Functions.Min(maxY+1, source.Height); int xStart = Functions.Max(minX, 0); int xEnd = Functions.Min(maxX+1, source.Width); for (int boxZ = zStart; boxZ < zEnd; ++boxZ) { bool notOnZBorder = (boxZ != minZ && boxZ != maxZ); for (int boxY = yStart; boxY < yEnd; ++boxY) { bool notOnYBorder = (boxY != minY && boxY != maxY); for (int boxX = xStart; boxX < xEnd; ++boxX) { bool notOnXBorder = (boxX != minX && boxX != maxX); if (notOnZBorder && notOnYBorder && notOnXBorder) continue; bool boxBoundary = boundary(source[boxX, boxY, boxZ]); if (srcBoundary != boxBoundary) minDistance = Functions.Min(minDistance, metric(srcX,srcY,srcZ,boxX,boxY,boxZ)); } } } //found closest opposite pixel if(minDistance != double.MaxValue) break; //not found any opposites yet, expand our search range boxSize += 2; } if(srcBoundary) dt[x, y, z] = new Colord(minDistance, 0, 0, 0); else dt[x, y, z] = new Colord(-minDistance, 0, 0, 0); } } } return dt; }
public Format(string name, Colord minColord, Colord maxColord, bool isNormalized, bool isCompressed) : base(name, minColord, maxColord, isNormalized, isCompressed) { }
public Colord[] GetPixels(int x, int y, int z, int width, int height, int depth) { Contract.Requires(x < Width && x >= 0, "x must be zero or greater, and less than the image width."); Contract.Requires(y < Height && y >= 0, "y must be zero or greater, and less than the image height."); Contract.Requires(z < Depth && z >= 0, "z must be zero or greater, and less than the image depth."); Contract.Requires(width > 0, "width must be greater than zero."); Contract.Requires(height > 0, "height must be greater than zero."); Contract.Requires(depth > 0, "depth must be greater than zero."); Contract.Requires(x + width < Width, "x plus width is greater than image width."); Contract.Requires(y + height < Height, "y plus height is greater than image height."); Contract.Requires(z + depth < Depth, "z plus depth is greater than image depth."); Colord[] pixels = new Colord[width * height * depth]; for (int destZ = 0, srcZ = z; destZ < depth; ++destZ, ++srcZ) { int destZOffset = destZ * height; for (int destY = 0, srcY = y; destY < height; ++destY, ++srcY) { int destYOffset = destY * width + destZOffset; for (int destX = 0, srcX = x; destX < width; ++destX, ++srcX) { int destOffset = destX + destYOffset; pixels[destOffset] = GetPixel(srcX,srcY,srcZ); } } } return pixels; }
static Colord Serp(Colord p0, Colord p1, Colord p2, Colord p3, double cint0, double cint1, double cint2, double cint3) { return(p0 * cint0 + p1 * cint1 + p2 * cint2 + p3 * cint3); }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) { throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); } //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); byte[] block = new byte[BlockSize]; Colord[] pixels = new Colord[16]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) { throw new System.IO.EndOfStreamException(); } read += bytes; } int mode = (block[0] & (-block[0])); switch (mode) { case 1: DecodeMode0(block, pixels); break; case 2: DecodeMode1(block, pixels); break; case 4: DecodeMode2(block, pixels); break; case 8: DecodeMode3(block, pixels); break; case 16: DecodeMode4(block, pixels); break; case 32: DecodeMode5(block, pixels); break; case 64: DecodeMode6(block, pixels); break; case 128: DecodeMode7(block, pixels); break; } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; int xy2index = y2 * 4; for (int x2 = 0; x2 < bwidth; ++x2) { destination[xyindex++] = pixels[xy2index++]; } } } //seek to next scan line source.Seek(rowPitch - ((sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - ((sourceBoxi.Height / 4) * (sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); Colord[] ccodes = new Colord[4]; double[] acodes = new double[8]; byte[] block = new byte[BlockSize]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) throw new System.IO.EndOfStreamException(); read += bytes; } // decompress the block int alpha0 = block[0]; int alpha1 = block[1]; ulong aindices = BitConverter.ToUInt16(block, 2) | ((ulong)BitConverter.ToUInt32(block, 4) << 16); //Only 6 bytes int color0 = BitConverter.ToUInt16(block, 8); int color1 = BitConverter.ToUInt16(block, 10); uint cindices = BitConverter.ToUInt32(block, 12); // unpack the endpoints ccodes[0] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color0)); ccodes[1] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color1)); // generate the midpoints ccodes[2] = Numerics.Color.Lerp(ccodes[0], ccodes[1], 1.0 / 3.0); ccodes[3] = Numerics.Color.Lerp(ccodes[0], ccodes[1], 2.0 / 3.0); //unpack alpha acodes[0] = alpha0 / 255.0; acodes[1] = alpha1 / 255.0; //generate midpoints if (alpha0 > alpha1) { acodes[2] = (6 * acodes[0] + 1 * acodes[1]) / 7.0; // bit code 010 acodes[3] = (5 * acodes[0] + 2 * acodes[1]) / 7.0; // bit code 011 acodes[4] = (4 * acodes[0] + 3 * acodes[1]) / 7.0; // bit code 100 acodes[5] = (3 * acodes[0] + 4 * acodes[1]) / 7.0; // bit code 101 acodes[6] = (2 * acodes[0] + 5 * acodes[1]) / 7.0; // bit code 110 acodes[7] = (1 * acodes[0] + 6 * acodes[1]) / 7.0; // bit code 111 } else { acodes[2] = (4 * acodes[0] + 1 * acodes[1]) / 5.0; // bit code 010 acodes[3] = (3 * acodes[0] + 2 * acodes[1]) / 5.0; // bit code 011 acodes[4] = (2 * acodes[0] + 3 * acodes[1]) / 5.0; // bit code 100 acodes[5] = (1 * acodes[0] + 4 * acodes[1]) / 5.0; // bit code 101 acodes[6] = 0.0; // bit code 110 acodes[7] = 1.0; // bit code 111 } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; for (int x2 = 0; x2 < bwidth; ++x2) { uint codeIndex = (cindices >> ((x2 + (y2 * 4)) << 1) & 3); ulong alphaIndex = (aindices >> ((x2 + (y2 * 4)) << 2)) & 7; destination[xyindex++] = new Numerics.Colord( ccodes[codeIndex].R, ccodes[codeIndex].G, ccodes[codeIndex].B, acodes[alphaIndex]); } } } //seek to next scan line source.Seek(rowPitch - ((sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - ((sourceBoxi.Height / 4) * (sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public static bool ThresholdBoundary(Colord value) { return(value.R >= 0.5); }
public override void GetBytes( Colord[] source, int index, int width, int height, System.IO.Stream destination, int rowPitch, int slicePitch, Boxi sourceBoxi, Point3i destinationPoint) { if ((destinationPoint.X & 0x3) != 0 || (destinationPoint.Y & 0x3) != 0) throw new ArgumentException("destinationPoint X and Y must be a multiple of 4.", "destinationPoint"); //seek to start destination.Seek( (destinationPoint.X / 4) * BlockSize + (destinationPoint.Y / 4) * rowPitch + destinationPoint.Z * slicePitch, System.IO.SeekOrigin.Current); // loop over blocks Internal.ColordSet colorSet = new Internal.ColordSet(Options.WeightColordByAlpha); Internal.ColordBlock colorBlock = new Internal.ColordBlock(); for (int z = 0; z < sourceBoxi.Depth; ++z) { for (int y = 0; y < sourceBoxi.Height; y+=4) { //write scan line for (int x = 0; x < sourceBoxi.Width; x+=4) { // compress the block colorSet.Map(source, index, sourceBoxi.X + x, sourceBoxi.Y + y, sourceBoxi.Z + z, width, height); //if (colorSet.Count != 1) // colorBlock = Internal.SingleColordFit.Fit(colorSet, Options); //else { switch (Options.Quality) { case Quality.Fastest: case Quality.Low: case Quality.Normal: case Quality.High: case Quality.Best: Internal.BoxiFit.Fit(colorBlock, colorSet, Options, true); break; //case Quality.Normal: // colorBlock = Internal.RangeFit.Fit(colorSet, Options, true); break; //case quality.High: // colorBlock = Internal.ClusterFit.Fit(colorSet, options, true, false); break; //case quality.Best: // colorBlock = Internal.ClusterFit.Fit(colorSet, options, true, true); break; default: break; } } // write the endpoints destination.WriteByte((byte)colorBlock.Colord0); destination.WriteByte((byte)(colorBlock.Colord0 >> 8)); destination.WriteByte((byte)colorBlock.Colord1); destination.WriteByte((byte)(colorBlock.Colord1 >> 8)); int indices = 0; for (int i = 0; i < 16; ++i) { indices |= (colorBlock.Indices[i] & 3) << (i << 1); } // write the indices destination.WriteByte((byte)indices); destination.WriteByte((byte)(indices >> 8)); destination.WriteByte((byte)(indices >> 16)); destination.WriteByte((byte)(indices >> 24)); } //seek to next scan line destination.Seek(rowPitch - (((sourceBoxi.Width + 3) / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice destination.Seek(slicePitch - (((sourceBoxi.Height + 3) / 4) * ((sourceBoxi.Width + 3) / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public static Image DistanceTransform( Image source, int width, int height, int depth, Func <Colord, bool> boundary, Metric metric) { Image dt = new Image(new Size3i(width, height, depth)); double zScale = depth == 1 ? 0 : (double)(source.Depth - 1) / (depth - 1); double yScale = height == 1 ? 0 : (double)(source.Height - 1) / (height - 1); double xScale = width == 1 ? 0 : (double)(source.Width - 1) / (width - 1); int spread = (int)Functions.Max(source.Width, Functions.Max(source.Height, Functions.Max(source.Depth, 3))); if (spread % 2 == 0) //0 % 2 == 0 { spread += 1; //spread must be odd and at least 3 } for (int z = 0; z < dt.Depth; ++z) { int srcZ = (int)(z * zScale); for (int y = 0; y < dt.Height; ++y) { int srcY = (int)(y * yScale); for (int x = 0; x < dt.Width; ++x) { int srcX = (int)(x * xScale); int boxSize = 3; double minDistance = double.MaxValue; bool srcBoundary = boundary(source[srcX, srcY, srcZ]); while (boxSize <= spread) { int minZ = srcZ - (boxSize / 2); int maxZ = srcZ + (boxSize / 2); int minY = srcY - (boxSize / 2); int maxY = srcY + (boxSize / 2); int minX = srcX - (boxSize / 2); int maxX = srcX + (boxSize / 2); int zStart = Functions.Max(minZ, 0); int zEnd = Functions.Min(maxZ + 1, source.Depth); int yStart = Functions.Max(minY, 0); int yEnd = Functions.Min(maxY + 1, source.Height); int xStart = Functions.Max(minX, 0); int xEnd = Functions.Min(maxX + 1, source.Width); for (int boxZ = zStart; boxZ < zEnd; ++boxZ) { bool notOnZBorder = (boxZ != minZ && boxZ != maxZ); for (int boxY = yStart; boxY < yEnd; ++boxY) { bool notOnYBorder = (boxY != minY && boxY != maxY); for (int boxX = xStart; boxX < xEnd; ++boxX) { bool notOnXBorder = (boxX != minX && boxX != maxX); if (notOnZBorder && notOnYBorder && notOnXBorder) { continue; } bool boxBoundary = boundary(source[boxX, boxY, boxZ]); if (srcBoundary != boxBoundary) { minDistance = Functions.Min(minDistance, metric(srcX, srcY, srcZ, boxX, boxY, boxZ)); } } } } //found closest opposite pixel if (minDistance != double.MaxValue) { break; } //not found any opposites yet, expand our search range boxSize += 2; } if (srcBoundary) { dt[x, y, z] = new Colord(minDistance, 0, 0, 0); } else { dt[x, y, z] = new Colord(-minDistance, 0, 0, 0); } } } } return(dt); }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) { throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); } //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); double[] rcodes = new double[16]; double[] gcodes = new double[16]; byte[] block = new byte[BlockSize]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) { throw new System.IO.EndOfStreamException(); } read += bytes; } // decompress the block int red0 = block[0]; int red1 = block[1]; ulong rindices = BitConverter.ToUInt16(block, 2) | ((ulong)BitConverter.ToUInt32(block, 4) << 16); //Only 6 bytes int green0 = block[8]; int green1 = block[9]; ulong gindices = BitConverter.ToUInt16(block, 10) | ((ulong)BitConverter.ToUInt32(block, 12) << 16); //Only 6 bytes // unpack the endpoints rcodes[0] = red0 / 255.0; rcodes[1] = red1 / 255.0; gcodes[0] = green0 / 255.0; gcodes[1] = green1 / 255.0; //generate midpoints if (red0 > red1) { rcodes[2] = (6 * rcodes[0] + 1 * rcodes[1]) / 7.0; // bit code 010 rcodes[3] = (5 * rcodes[0] + 2 * rcodes[1]) / 7.0; // bit code 011 rcodes[4] = (4 * rcodes[0] + 3 * rcodes[1]) / 7.0; // bit code 100 rcodes[5] = (3 * rcodes[0] + 4 * rcodes[1]) / 7.0; // bit code 101 rcodes[6] = (2 * rcodes[0] + 5 * rcodes[1]) / 7.0; // bit code 110 rcodes[7] = (1 * rcodes[0] + 6 * rcodes[1]) / 7.0; // bit code 111 } else { rcodes[2] = (4 * rcodes[0] + 1 * rcodes[1]) / 5.0; // bit code 010 rcodes[3] = (3 * rcodes[0] + 2 * rcodes[1]) / 5.0; // bit code 011 rcodes[4] = (2 * rcodes[0] + 3 * rcodes[1]) / 5.0; // bit code 100 rcodes[5] = (1 * rcodes[0] + 4 * rcodes[1]) / 5.0; // bit code 101 rcodes[6] = 0.0; // bit code 110 rcodes[7] = 1.0; // bit code 111 } if (green0 > green1) { gcodes[2] = (6 * gcodes[0] + 1 * gcodes[1]) / 7.0; // bit code 010 gcodes[3] = (5 * gcodes[0] + 2 * gcodes[1]) / 7.0; // bit code 011 gcodes[4] = (4 * gcodes[0] + 3 * gcodes[1]) / 7.0; // bit code 100 gcodes[5] = (3 * gcodes[0] + 4 * gcodes[1]) / 7.0; // bit code 101 gcodes[6] = (2 * gcodes[0] + 5 * gcodes[1]) / 7.0; // bit code 110 gcodes[7] = (1 * gcodes[0] + 6 * gcodes[1]) / 7.0; // bit code 111 } else { gcodes[2] = (4 * gcodes[0] + 1 * gcodes[1]) / 5.0; // bit code 010 gcodes[3] = (3 * gcodes[0] + 2 * gcodes[1]) / 5.0; // bit code 011 gcodes[4] = (2 * gcodes[0] + 3 * gcodes[1]) / 5.0; // bit code 100 gcodes[5] = (1 * gcodes[0] + 4 * gcodes[1]) / 5.0; // bit code 101 gcodes[6] = 0.0; // bit code 110 gcodes[7] = 1.0; // bit code 111 } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; for (int x2 = 0; x2 < bwidth; ++x2) { ulong rindex = (rindices >> ((x2 + (y2 * 4)) << 2)) & 7; ulong gindex = (gindices >> ((x2 + (y2 * 4)) << 2)) & 7; destination[xyindex++] = new Colord( rcodes[rindex], gcodes[gindex], 0.0); } } } //seek to next scan line source.Seek(rowPitch - ((sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - ((sourceBoxi.Height / 4) * (sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
static Colord Lerp(Colord p0, Colord p1, double f) { return(p0 + f * (p1 - p0)); }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((width & 0x3) != 0 || (height & 0x3) != 0) throw new ArgumentException("sourceSize Width and Height must be a multiple of 4.", "sourceSize"); if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); double[] rcodes = new double[16]; byte[] block = new byte[BlockSize]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) throw new System.IO.EndOfStreamException(); read += bytes; } // decompress the block int red0 = block[0]; int red1 = block[1]; ulong rindices = BitConverter.ToUInt16(block, 2) | ((ulong)BitConverter.ToUInt32(block, 4) << 16); //Only 6 bytes // unpack the endpoints rcodes[0] = red0 / 255.0; rcodes[1] = red1 / 255.0; //generate midpoints if (red0 > red1) { rcodes[2] = (6 * rcodes[0] + 1 * rcodes[1]) / 7.0; // bit code 010 rcodes[3] = (5 * rcodes[0] + 2 * rcodes[1]) / 7.0; // bit code 011 rcodes[4] = (4 * rcodes[0] + 3 * rcodes[1]) / 7.0; // bit code 100 rcodes[5] = (3 * rcodes[0] + 4 * rcodes[1]) / 7.0; // bit code 101 rcodes[6] = (2 * rcodes[0] + 5 * rcodes[1]) / 7.0; // bit code 110 rcodes[7] = (1 * rcodes[0] + 6 * rcodes[1]) / 7.0; // bit code 111 } else { rcodes[2] = (4 * rcodes[0] + 1 * rcodes[1]) / 5.0; // bit code 010 rcodes[3] = (3 * rcodes[0] + 2 * rcodes[1]) / 5.0; // bit code 011 rcodes[4] = (2 * rcodes[0] + 3 * rcodes[1]) / 5.0; // bit code 100 rcodes[5] = (1 * rcodes[0] + 4 * rcodes[1]) / 5.0; // bit code 101 rcodes[6] = 0.0; // bit code 110 rcodes[7] = 1.0; // bit code 111 } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; for (int x2 = 0; x2 < bwidth; ++x2) { ulong rindex = (rindices >> ((x2 + (y2 * 4)) << 2)) & 7; destination[xyindex++] = new Colord( rcodes[rindex], 0.0, 0.0); } } } //seek to next scan line source.Seek(rowPitch - ((sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - ((sourceBoxi.Height / 4) * (sourceBoxi.Width / 4) * BlockSize), System.IO.SeekOrigin.Current); } }
public override void GetColords( System.IO.Stream source, int rowPitch, int slicePitch, Colord[] destination, int index, int width, int height, Boxi sourceBoxi, Point3i destinationPoint) { if ((sourceBoxi.X & 0x3) != 0 || (sourceBoxi.Y & 0x3) != 0) { throw new ArgumentException("sourceBoxi X and Y must be a multiple of 4.", "sourceBoxi"); } //seek to start source.Seek( (sourceBoxi.X / 4) * BlockSize + (sourceBoxi.Y / 4) * rowPitch + sourceBoxi.Z * slicePitch, System.IO.SeekOrigin.Current); Colord[] codes = new Colord[4]; byte[] block = new byte[BlockSize]; // loop over blocks for (int z = 0; z < sourceBoxi.Depth; ++z) { int zindex = index + (destinationPoint.Z + z) * (height * width); for (int y = 0; y < sourceBoxi.Height; y += 4) { //read scan line for (int x = 0; x < sourceBoxi.Width; x += 4) { //read block int read = 0; while (read < BlockSize) { int bytes = source.Read(block, read, BlockSize - read); if (bytes == 0) { throw new System.IO.EndOfStreamException(); } read += bytes; } // decompress the block int color0 = BitConverter.ToUInt16(block, 0); int color1 = BitConverter.ToUInt16(block, 2); uint indices = BitConverter.ToUInt32(block, 4); // unpack the endpoints codes[0] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color0)); codes[1] = Color.Unquantized(5, 6, 5, Vector.Unpack(5, 6, 5, color1)); // generate the midpoints if (color0 > color1) { codes[2] = Numerics.Color.Lerp(codes[0], codes[1], 1.0 / 3.0); codes[3] = Numerics.Color.Lerp(codes[0], codes[1], 2.0 / 3.0); } else { codes[2] = Numerics.Color.Lerp(codes[0], codes[1], 1.0 / 2.0); codes[3] = new Numerics.Colord(0.0, 0.0, 0.0, 0.0); } int bwidth = Functions.Min(4, width - (destinationPoint.X + x)); int bheight = Functions.Min(4, height - (destinationPoint.Y + y)); for (int y2 = 0; y2 < bheight; ++y2) { int xyindex = (destinationPoint.X + x) + (destinationPoint.Y + y + y2) * width + zindex; for (int x2 = 0; x2 < bwidth; ++x2) { uint codeIndex = (indices >> ((x2 + (y2 * 4)) << 1) & 3); destination[xyindex++] = codes[codeIndex]; } } } //seek to next scan line source.Seek(rowPitch - (((sourceBoxi.Width + 3) / 4) * BlockSize), System.IO.SeekOrigin.Current); } //seek to next scan slice source.Seek(slicePitch - (((sourceBoxi.Height + 3) / 4) * ((sourceBoxi.Width + 3) / 4) * BlockSize), System.IO.SeekOrigin.Current); } }