ushort array to Image object - c#

I have an array of ushort pixel data that I need to save as a jpeg file. From what I've found I can do this by using
Image.Save(path, ImageFormat.Jpeg);
but I don't know how to get the ushort data into the Image object. I've found ways to do this with byte arrays but not ushort.
I've spent far to much time trying to figure this out so now I ask the mighty StackOverflow, How do I this?
Edit:
Sorry, the ushorts are 16 bit grayscale values.

I think you have to actually create a Bitmap, draw the pixels onto it and save it afterwards.
Something like this:
var bitmap = new Bitmap(sizeX, sizeY, Imaging.PixelFormat.Format16bppGrayScale)
for (y = 0; ...)
for (x = 0; ...)
{
bitmap.SetPixel(x, y, color information from ushort array);
}
bitmap.Save("filename.jpg", ImageFormat.Jpeg);
Note that I don't know how to get a 16 bit greyscale color information into the Color struct.

This is a complete working example based on the accepted answer:
public static void SaveJpg(string fileName,int sizeX,int sizeY,ushort [] imData)
{
var bitmap = new Bitmap(sizeX, sizeY, PixelFormat.Format48bppRgb);
int count = 0;
for (int y = 0; y < sizeY; y++)
{
for (int x = 0; x < sizeX; x++)
{
bitmap.SetPixel(x, y, Color.FromArgb(imData[count], imData[count], imData[count]));
count++;
}
}
bitmap.Save(fileName, ImageFormat.Jpeg);
}

I believe you want to use the Bitmap class, which inherits from Image. This MSDN reference may assist.

Related

Is there a way of extracting the index of a pixel in an indexed colour Bitmap (C#)?

I've loaded an indexed colour image (8bppI) with a unique palette into a C# program and I need to access the index of colours in that image. However, the only access function seems to be Bitmap.GetPixel(x,y) which returns a colour, not an index. When that same colour is inserted back into a Bitmap of the same format and palette, the colour information is apparently misinterpreted as an index and everything goes to heck. Here's a simplified version of the code for clarity of the issue:
public void CreateTerrainMap() {
visualization = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
visualizationLock = new LockBitmap(visualization);
Lock();
// "TerrainIndex.bmp" is a 256x256 indexed colour image (8bpp) with a unique palette.
// Debugging confirms that this image loads with its palette and format intact
Bitmap terrainColours = new Bitmap("Resources\\TerrainIndex.bmp");
visualization.Palette = terrainColours.Palette;
Color c;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (Terrain[x, y] < SeaLevel) {
c = Color.FromArgb(15); // Counterintuitively, this actually gives index 15 (represented as (0,0,0,15))
} else {
heatIndex = <some number between 0 and 255>;
rainIndex = <some number between 0 and 255>;
if (IsCoastal(x, y)) {
c = Color.FromArgb(35); // Counterintuitively, this actually gives index 35 (represented as (0,0,0,35))
} else {
// This returns an argb colour rather than an index...
c = terrainColours.GetPixel(rainIndex, heatIndex);
}
}
// ...and this seemingly decides that the blue value is actually an index and sets the wrong colour entirely
visualizationLock.SetPixel(x, y, c);
}
}
}
TerrainIndex looks like this:
TerrainIndex.bmp
The palette looks like this: Palette
The output should look like this: Good
But it looks like this instead: Bad
Note that the oceans (index 15) and coasts (index 35) look correct, but everything else is coming from the wrong part of the palette.
I can't find any useful information on working with indexed colour bitmaps in C#. I really hope someone can explain to me what I might be doing wrong, or point me in the right direction.
I created an answer from my comment. So the "native" solution is something like this (requires allowing unsafe code):
Bitmap visualization = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
visualization.Palette = GetVisualizationPalette();
BitmapData visualizationData = visualization.LockBits(new Rectangle(Point.Empty, visualization.Size),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
try
{
unsafe
{
byte* row = (byte*)visualizationData.Scan0;
for (int y = 0; y < visualizationData.Height; y++)
{
for (int x = 0; x < visualizationData.Width; x++)
{
// here you set the 8bpp palette index directly
row[x] = GetHeatIndex(x, y);
}
row += visualizationData.Stride;
}
}
}
finally
{
visualization.UnlockBits(visualizationData);
}
Or, you can use these libraries, and then:
using KGySoft.Drawing;
using KGySoft.Drawing.Imaging;
// ...
Bitmap visualization = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
visualization.Palette = GetVisualizationPalette();
using (IWritableBitmapData visualizationData = visualization.GetWritableBitmapData())
{
for (int y = 0; y < visualizationData.Height; y++)
{
IWritableBitmapDataRow row = visualizationData[y];
for (int x = 0; x < visualizationData.Width; x++)
{
// setting pixel by palette index
row.SetColorIndex(x, GetHeatIndex(x, y));
// or: directly by raw data (8bpp means 1 byte per pixel)
row.WriteRaw<byte>(x, GetHeatIndex(x, y));
// or: by color (automatically applies the closest palette index)
row.SetColor(x, GetHeatColor(x, y));
}
}
}
Edit:
And for reading pixels/indices you can use terrainColors.GetReadableBitmapData() so you will able to use rowTerrain.GetColorIndex(x) or rowTerrain.ReadRaw<byte>(x) in a very similar way.

Why is AForge.net giving a different output in case of FFT Auto-correlation?

See this related question.
I want to obtain the same outcome using AForge.net framework. The output should match the following:
The output seems to be not coming as expected:
Why is the output different in AForge.net?
.
Source Code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Bitmap image = (Bitmap)Bitmap.FromFile(#"StandardImage\\lena.png");
Bitmap conv = new Bitmap(image.Width, image.Height, image.PixelFormat);
ComplexImage cImage = ComplexImage.FromBitmap(image);
cImage.ForwardFourierTransform();
ComplexImage cKernel = ComplexImage.FromBitmap(image);
cImage.ForwardFourierTransform();
ComplexImage convOut = ComplexImage.FromBitmap(conv);
convOut.ForwardFourierTransform();
for (int y = 0; y < cImage.Height; y++)
{
for (int x = 0; x < cImage.Width; x++)
{
convOut.Data[x, y] = cImage.Data[x, y] * cKernel.Data[x, y];
}
}
convOut.BackwardFourierTransform();
Bitmap bbbb = convOut.ToBitmap();
pictureBox1.Image = bbbb;
}
}
The main problem is
ComplexImage cKernel = ComplexImage.FromBitmap(image);
//cImage.ForwardFourierTransform(); //<--- This line should be FFT of cKernel
cKernel.ForwardFourierTransform();
This would solve the problem you mentioned in the resulting image, but if you want to get an image similar to the bottom right image you need to do some normalization to increase the intensity of pixels.
update:
The bottom right image is actually a Fourier image so I think we should remove the BFF.
//convOut.BackwardFourierTransform();
It is seems like you are not using a gaussian kernel with Aforge,
Anyway, the library has a method for convolution with gaussian:
int w=4,h=11;
GaussianBlur filter = new GaussianBlur( w, h );
// apply the filter
filter.ApplyInPlace( image );
Try it and the output should be the same as the others.

Implementation of Bit-Plane Decomposition c#

Tried to implement a bpcs-steganography, and one of the first problem i faced was bit-plane decomposition.
I've created a method (GetBitPlaneRed) (only for Red yet, but it seems the same for other colors) which creates a red-and-white bitmap based on the original bitmap and the index of bit plane (from 1 to 8).
private static int GetBit(byte b, int bitIndex)
{
return (b >> bitIndex) & 0x01;
}
private static Bitmap GetBitPlaneRed(Bitmap bitmap, int bitPlaneIndex)
{
Bitmap newBitmap = new Bitmap(bitmap.Width, bitmap.Height);
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color currColor = bitmap.GetPixel(i, j);
int bit = GetBit(currColor.R, bitPlaneIndex);
Color newColor = Color.FromArgb(255, 255 * bit, 255 * bit);
newBitmap.SetPixel(i, j, newColor);
}
}
return newBitmap;
}
Seems, it works allright for the MSB (most significant bit), but for other bit planes it's not so correct. Here are some result pictures that i've got to comparison with the right ones.
[EDIT] The "right results" are from a scientific article about BPCS steganography written by Eiji Kawaguchi, so i trust that source. Also, it seems that the mistake is in the way i save my bit-plane images, so i've added some peace of code here where i save my bit-plane images.
Added an original image as well.
private static void SaveBitPlanes()
{
string filePath = "monalisa.jpg";
string ext = System.IO.Path.GetExtension(filePath);
Bitmap bitmap = new Bitmap(filePath);
ImageFormat imageFormat = bitmap.RawFormat;
for (int i = 0; i < 8; i++)
{
Bitmap newBitmap = GetBitPlaneRed(bitmap, i);
newBitmap.Save("bitPlaneRed" + i + ext, imageFormat);
}
}
Original image:
My result of MSB plane:
My result of bit plane #3:
My result of bit plane #7:
Right results:
I would appreciate any help or advice.
There are all important stuff I figured out during existance of this question.
All code I wrote in main post is correct.
Difference in images is not connected with jpeg compression or any
other compression. It works for any file format.
The reason why my results were not similar to those results in an
article is that I used a low-quality image as a source. After I tried
some other high quality images, results look nice and pretty
detailed.
Thank everybody for helping me in figuring out all these points!

fast way to split 8bit bitmap into eight differet 1bit bitmaps

I need a way to convert 1000+ 8bit bitmaps into eight 1bit bitmaps.
Currently I am running two loops which read each pixel from the main image and assign it a 1bpp image. It takes a very long time to accomplish this, anyway better to do it?
Here is an example of my code (separates only into two images):
Bitmap rawBMP = new Bitmap(path);
Bitmap supportRAW = new Bitmap(rawBMP.Width, rawBMP.Height);
Bitmap modelRAW = new Bitmap(rawBMP.Width, rawBMP.Height);
Color color = new Color();
for (int x = 0; x < rawBMP.Width; x++)
{
for (int y = 0; y < rawBMP.Height; y++)
{
color = rawBMP.GetPixel(x, y);
if (color.R == 166) //model
{
modelRAW.SetPixel(x, y, Color.White);
}
if (color.R == 249) //Support
{
supportRAW.SetPixel(x, y, Color.White);
}
}
}
var supportBMP = supportRAW.Clone(new Rectangle(0, 0, rawBMP.Width, rawBMP.Height), System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
var modelBMP = modelRAW.Clone(new Rectangle(0, 0, rawBMP.Width, rawBMP.Height), System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
If you have to check every pixel then you are going to have to loop through them all at least once, however like TaW suggest there are more efficient ways to access pixels.
SetPixel and GetPixel are much slower then you accessing the data directly, Look at the use of unsafe to get direct access to the data, or marshaling to copy the data back and forth.
( see https://stackoverflow.com/a/1563170 for a more detailed written by notJim)

Algorithm for finding a painted region on a canvas

Update: I am attempting to pull a little clutter out of this post and sum it up more concisely. Please see the original edit if needed.
I am currently attempting to trace a series of single colored blobs on a Bitmap canvas.
e.g. An example of the bitmap I am attempting to trace would look like the following:
alt text http://www.refuctored.com/polygons.bmp
After successfully tracing the outlines of the 3 blobs on the image, I would have a class that held the color of a blob tied to a point list representing the outline of the blob (not all the pixels inside of the blobs).
The problem I am running into is logic in instances where a neighboring pixel has no surrounding pixels other than the previous pixel.
e.g The top example would trace fine, but the second would fail because the pixel has no where to go since the previous pixels have already been used.
alt text http://www.refuctored.com/error.jpg
I am tracing left-to-right, top-to-bottom, favoring diagonal angles over right angles. I must be able to redraw an exact copy of the region based off the data I extract, so the pixels in the list must be in the right order for the copy to work.
Thus far, my attempt has been riddled with failure, and a couple days of pulling my hair out trying to rewrite the algorithms a little different each time to solve the issue. Thus far I have been unsuccessful. Has anyone else had a similar issue like mine who has a good algorithm to find the edges?
One simple trick to avoiding these cul-de-sacs is to double the size of the image you want to trace using a nearest neighbor scaling algorithm before tracing it. Like that you will never get single strips.
The alternative is to use a marching squares algorithm - but it seems to still have one or two cases where it fails: http://www.sakri.net/blog/2009/05/28/detecting-edge-pixels-with-marching-squares-algorithm/
Have you looked at blob detection algorithms? For example, http://opencv.willowgarage.com/wiki/cvBlobsLib if you can integrate OpenCV into your application. Coupled with thresholding to create binary images for each color (or color range) in your image, you could easily find the blobs that are the same color. Repeat for each color in the image, and you have a list of blobs sorted by color.
If you cannot use OpenCV directly, perhaps the paper referenced by that library ("A linear-time component labeling algorithm using contour tracing technique", F.Chang et al.) would provide a good method for finding blobs.
Rather than using recursion, use a stack.
Pseudo-code:
Add initial pixel to polygon
Add initial pixel to stack
while(stack is not empty) {
pop pixel off the stack
foreach (neighbor n of popped pixel) {
if (n is close enough in color to initial pixel) {
Add n to polygon
Add n to stack
}
}
}
This will use a lot less memory than the same solution using recursion.
Just send your 'Image' to BuildPixelArray function and then call the FindRegions.
After that the 'colors' variable will be holding your colors list and pixel coordinates in every list member.
I've copied the source from one of my projects, there may be some undefined variables or syntax erors.
public class ImageProcessing{
private int[,] pixelArray;
private int imageWidth;
private int imageHeight;
List<MyColor> colors;
public void BuildPixelArray(ref Image myImage)
{
imageHeight = myImage.Height;
imageWidth = myImage.Width;
pixelArray = new int[imageWidth, imageHeight];
Rectangle rect = new Rectangle(0, 0, myImage.Width, myImage.Height);
Bitmap temp = new Bitmap(myImage);
BitmapData bmpData = temp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int remain = bmpData.Stride - bmpData.Width * 3;
unsafe
{
byte* ptr = (byte*)bmpData.Scan0;
for (int j = 15; j < bmpData.Height; j++)
{
for (int i = 0; i < bmpData.Width; i++)
{
pixelArray[i, j] = ptr[0] + ptr[1] * 256 + ptr[2] * 256 * 256;
ptr += 3;
}
ptr += remain;
}
}
temp.UnlockBits(bmpData);
}
public void FindRegions()
{
colors = new List<MyColor>();
for (int i = 0; i < imageWidth; i++)
{
for (int j = 0; j < imageHeight; j++)
{
int tmpColorValue = pixelArray[i, j];
MyColor tmp = new MyColor(tmpColorValue);
if (colors.Contains(tmp))
{
MyColor tmpColor = (from p in colors
where p.colorValue == tmpColorValue
select p).First();
tmpColor.pointList.Add(new MyPoint(i, j));
}
else
{
tmp.pointList.Add(new MyPoint(i, j));
colors.Add(tmp);
}
}
}
}
}
public class MyColor : IEquatable<MyColor>
{
public int colorValue { get; set; }
public List<MyPoint> pointList = new List<MyPoint>();
public MyColor(int _colorValue)
{
colorValue = _colorValue;
}
public bool Equals(MyColor other)
{
if (this.colorValue == other.colorValue)
{
return true;
}
return false;
}
}
public class MyPoint
{
public int xCoord { get; set; }
public int yCoord { get; set; }
public MyPoint(int _xCoord, int _yCoord)
{
xCoord = _xCoord;
yCoord = _yCoord;
}
}
If you're getting a stack overflow I would guess that you're not excluding already-checked pixels. The first check on visiting a square should be whether you've been here before.
Also, I was working on a related problem not too long ago and I came up with a different approach that uses a lot less memory:
A queue:
AddPointToQueue(x, y);
repeat
x, y = HeadItem;
AddMaybe(x - 1, y); x + 1, y; x, y - 1; x, y + 1;
until QueueIsEmpty;
AddMaybe(x, y):
if Visited[x, y] return;
Visited[x, y] = true;
AddPointToQueue(x, y);
The point of this approach is that you end up with your queue basically holding a line wrapped around the mapped area. This limits memory usage better than a stack can.
If relevant it also can be trivially modified to yield the travel distance to any square.
Try using AForge.net. I would go for Filter by colors, Threshold and then you could do some Morphology to decrement the black/White zones to lose contact between the objects. Then you could go for the Blobs.

Categories

Resources