c# WIA 12 bit grayscale image loses quality as bitmap - winforms

I am writing a windows forms application. I have an Image, received from CCD camera. The camera takes 12 bit grayscale tiff – 2 bytes per pixel. To receive it I am using WIA(windows image acquisition). I can make a byte array from the image data. After that I need to display the image in picturebox. When shown in picturebox, the image is too dark. Also, the created bitmap is Format32bppArgb. Do I lose quality, when creating the bitmap and how can I make the needed bitmap format? I am extremely new to image processing and any help will be great. I have read many forum posts on the topic of conversion between the formats, but with no luck so far.
So any ideas how to receive 16 bit grayscale bitmap from what I have so far?
Edit: This now is working:
private void btnAdvancedTestSnap_Click(object sender, EventArgs e)
{
WIA.CommonDialog _dialog = new CommonDialogClass();
WIA.Device _camera = _dialog.ShowSelectDevice(WIA.WiaDeviceType.CameraDeviceType, false, false);
ImageFile imageFile = (ImageFile)_camera.Items[1].Transfer(EnvFormatID.wiaFormatTIFF);
Byte[] receivedBytes = (byte[])imageFile.FileData.get_BinaryData();
int bytecount = receivedBytes.Length;
int width = imageFile.Width;
int height = imageFile.Height;
int dimension = width * height * 2;//number of bytes representing the image - 2 bytes per pixel
int startImgBytes = bytecount - dimension;
startImgBytes += 1;// from which position of the big array to start making pixel values
byte[] imageBytes = new byte[dimension]; //byte array with only bytes,representing the picture
int j = 0;
for (int i = startImgBytes; i < receivedBytes.Length; i++)//filling the only pixel byte data array
{
imageBytes[j] = receivedBytes[i];
j++;
}
int pixDimension = width * height; //number of pixels in the image
int[] pixVal = new int[pixDimension];
int z = 0;
for (int i = 0; i < imageBytes.Length; i+=2)
{
int res = (imageBytes[i] * 0x100) + imageBytes[i + 1];//int value of the pixel, 2 bytes per pixel
int pix = (res * 255) / 4095;// scalling down to 8 bit value
pixVal[z] = pix;
z++;
}
Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);
Color p;
//grayscale
int counter = 0;
for (int y = 0; y < height; y++)//height
{
for (int x = 0; x < width; x++)//width
{
int val = pixVal[counter];
newImage.SetPixel(x,y,Color.FromArgb(255,val,val,val));
counter++;
}
}
pbAdvanced.Image = newImage; //show the image in picture box
But this method is very slow for high resolution. Any ideas how to improve the speed. I read examples with Marshal.Copy and lockbits, but in all examples they use a source image and copy to new. Any help will be greately appreciated

Related

How can I fix this error : 'Cannot invoke loadPixels() on the array type PImage[]'?

I'm kind of a beginner with Processing and I've been having difficulty with my pixel array. I have 10 images numbered from 0-9 that are being shown one after another... What I am trying to do on top of that is take each image and change its brightness level, turning it either white or black.
I've already tried to just change the brightness using one image, so not an array of images which works perfectly! But when joining those two together it doesn't work for me.
int maxImages = 10; // The number of frames in the animation
int imageIndex = 00; //initial image to be displayed first
PImage[] picture = new PImage[maxImages]; //the image array
void setup() {
size(500, 500); //size of sketch
frameRate(1); //frames processed per second
//loading images with numbered files into the array
for (int i = 0; i< picture.length; i++) {
picture[i] = loadImage("spast_" + i + ".jpg");
}
}
void draw() {
image(picture[imageIndex], 0, 0); //dispaying one image
loadPixels(); //accessing pixels
picture.loadPixels(); //accessing the image pixels too
//THIS is where it stops me and gives me 'Cannot invoke loadPixels() on the array type PImage[]'
for (int x = 0; x < width; x++) { //loops through every single x value
for (int y = 0; y < height; y++) { //loops through every single y value
int loc = x + y*width; // declare integer loc
float b = brightness(picture.pixels[loc]); //give me the brightness of pixels
if (b < 150) { //if the pixel is lower than 150
pixels[loc] = color(0); //then make those pixels black
} else { //otherwise
pixels[loc] = color(255); //make pixels white
}
}
}
imageIndex = (imageIndex + 1) % picture.length; //increment image index by one each cycle
updatePixels(); //when finished with the pixel array update the pixels
}
I'm expecting as each image is displayed it brightness value is changed and then it goes on to image 2 and so on...
Your picture variable is an array of PImage instances. You can't call loadPixels() on the array itself. You have to get a PImage at a specific index of the array, and then call the loadPixels() function on that instance.
Here's an example:
picture[0].loadPixels();
This line of code gets the PImage at index 0 and calls the loadPixels() function on it.
Note that you're already doing something pretty similar with this line:
image(picture[imageIndex], 0, 0);
Shameless self-promotion: here is a tutorial on arrays in Processing.
This is the updated and working code:
int maxImages = 10; // The number of frames in the animation
int imageIndex = 0; //initial image to be displayed first
PImage[] picture = new PImage[maxImages]; //the image array
void setup() {
size(500, 500); //size of sketch
frameRate(1); //frames processed per second
//loading images with numbered files into the array
for (int i = 0; i< picture.length; i++) {
picture[i] = loadImage("spast_" + i + ".jpg");
}
}
void draw() {
loadPixels(); //accessing pixels
image(picture[imageIndex], 0, 0); //dispaying one image
imageIndex = (imageIndex + 1) % picture.length; //increment image index by one each cycle
picture[imageIndex].loadPixels(); //accessing the image pixels in the array
for (int x = 0; x < width; x++) { //loops through every single x value
for (int y = 0; y < height; y++) { //loops through every single y value
int loc = x + y*width; // declare integer loc
float b = brightness(picture[imageIndex].pixels[loc]); //give me the brightness of pixels
if (b < 150) { //if the pixel is lower than 150
pixels[loc] = color(0); //then make those pixels black
} else { //otherwise
pixels[loc] = color(255); //make pixels white
}
}
}
updatePixels(); //when finished with the pixel array update the pixels
}

ImageMagick to write image file row by row (or band by band)

Does ImageMagick (C API MagickWand) have a functionality to generate an image file (.jpg, .tif) using RGB raster data?
If so, can it also generate an image file band by band, meaning write few rows at a time until it writes the whole image? Or one row at a time?
I believe you are describing image row iterators. ImageMagick provided PixelIterator methods to allow traversing of image data.
Here's a quick example.
#include <stdio.h>
#include <wand/MagickWand.h>
int main(int argc, const char * argv[]) {
// Set up IM environment.
MagickWandGenesis();
// Prototype
MagickWand * wand;
PixelWand * bg;
PixelIterator * iter;
PixelWand ** row;
MagickPixelPacket pixel;
size_t
x,
y,
row_width,
width = 200,
height = 50;
unsigned int
seed = 0xABCD;
// Allocate & initialize.
wand = NewMagickWand();
bg = NewPixelWand();
// Create an empty image.
PixelSetColor(bg, "WHITE");
MagickNewImage(wand, width, height, bg);
// Free color resource.
bg = DestroyPixelWand(bg);
srand(seed); // Seed random number.
// Allocate & initialize pixel iterator
iter = NewPixelIterator(wand);
// Loop through all rows.
for (y = 0; y < height; ++ y)
{
// Pull all pixels in a row.
row = PixelGetNextIteratorRow(iter, &row_width);
// Iterate over all pixels collected.
for (x = 0; x < row_width; ++x)
{
// Copy pixel data to packet.
PixelGetMagickColor(row[x], &pixel);
// Set random colors.
pixel.red = rand() & QuantumRange;
pixel.green = rand() & QuantumRange;
pixel.blue = rand() & QuantumRange;
// Put data back to pixel from packet.
PixelSetMagickColor(row[x], &pixel);
}
// Sync manipulated data on buffer back to image.
PixelSyncIterator(iter);
}
/******************************
Let's set row 16 to be all RED
******************************/
PixelSetIteratorRow(iter, 15);
row = PixelGetNextIteratorRow(iter, &row_width);
for (x = 0; x < row_width; ++x)
{
PixelGetMagickColor(row[x], &pixel);
pixel.red = QuantumRange;
pixel.green = 0;
pixel.blue = 0;
PixelSetMagickColor(row[x], &pixel);
}
// Sync manipulated data on buffer back to image.
PixelSyncIterator(iter);
// Free iterator resorce.
iter = DestroyPixelIterator(iter);
MagickWriteImage(wand, "/tmp/output.png");
// Free image data.
wand = DestroyMagickWand(wand);
MagickWandTerminus();
return 0;
}
Please note that the above example uses ImageMagick 6. For ImageMagick 7, please review Porting Guide.

Crop an image from a byte array

I have an image (which is a Sprite) that I store it in a byte array.
I would like to extract only the bytes that relate to a specific place and size within this byte array so that I can create a new image, basically a crop.
I am using C# and compact cf. I could use get pixel and save each value to a byte array and then 'read' the portion i am interested back. I know I can use LockBitmap() to make this quicker. I would normally use Aforge and/or Emgu but as I say I am using the compact cf framework 2.
I would be interested in any known ways to do this.
Thanks
Additional.
Following on the link below I would like to know whether there is an alternative (like a buffer copy) to this iterative piece of code?
//Iterate the selected area of the original image, and the full area of the new image
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width * BPP; j += BPP)
{
int origIndex = (startX * rawOriginal.Stride) + (i * rawOriginal.Stride) + (startY * BPP) + (j);
int croppedIndex = (i * width * BPP) + (j);
//copy data: once for each channel
for (int k = 0; k < BPP; k++)
{
croppedBytes[croppedIndex + k] = origBytes[origIndex + k];
}
}
}
I understand that this is an old question, but here's my take on it:
public static byte[] CropImageArray(byte[] pixels, int sourceWidth, int bitsPerPixel, Int32Rect rect)
{
var blockSize = bitsPerPixel / 8;
var outputPixels = new byte[rect.Width * rect.Height * blockSize];
//Create the array of bytes.
for (var line = 0; line <= rect.Height - 1; line++)
{
var sourceIndex = ((rect.Y + line) * sourceWidth + rect.X) * blockSize;
var destinationIndex = line * rect.Width * blockSize;
Array.Copy(pixels, sourceIndex, outputPixels, destinationIndex, rect.Width * blockSize);
}
return outputPixels;
}
You'll need to know the bits per pixel and the width. You'll be using one for instead of two.
I have some more links for you
Try out if you find you solution or it helps you in any way
1)http://www.codeproject.com/Articles/33838/Image-Processing-using-C
2)http://codenicely.blogspot.in/2012/03/how-to-crop-image-in-c.html

Opencv corners detection for High resolution images

I've just implemented corner detection using OpenCV and i got the corner value as zero.i use 3488*2616 resolution camera images.it is there any proper way to find the corner detection for high resolution images.i d'not know where i did my mistake.Here with i've attached my code and images also.please help me.i'm very new to opencv.sorry for my English.
int board_w = 6;
int board_h = 6;
const int MAX_CORNERS = 500;
int main()
{
int board_n = (board_w-1) * (board_h-1);
CvSize board_sz = cvSize( board_w-1, board_h-1 );
CvPoint2D32f* corners = new CvPoint2D32f[board_n];
int cornerCount = 0;
IplImage *image = cvLoadImage("myimage.jpg");
IplImage *gray_image = cvCreateImage(cvGetSize(image),8,1);
cvCvtColor(image, gray_image, CV_BGR2GRAY );
const int N = cvFindChessboardCorners(gray_image,board_sz,&corners[0],&cornerCount,10);
cvFindCornerSubPix(gray_image,&corners[0],cornerCount,cvSize(3,3),cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_EPS,0,.01));
printf("\ the count was:%d \n",cornerCount);
for (int i = 0; i < cornerCount; i++)
{
cvCircle (image, cvPointFrom32f (corners[i]), 3, CV_RGB (0, 0, 255), 2);
}
cvNamedWindow("firstframe");
cvShowImage("firstframe",image);
cvWaitKey(0);
cvReleaseImage(&image);
cvReleaseImage(&gray_image);
}
The code will work for normal chessboard images.but while using real time camera images with that resolution it ll not works.please help me.thanks in advance.
If you suspect that detection is really failing simply because you are using high resolution images, you can always cvResize() your IplImage to a smaller size and verify your observation.

How to slice/cut an image into pieces

So I have a function that receives OpenCV image and turns it into gray-scale.
void UseLSD(IplImage* destination)
{
IplImage *destinationForGS = cvCreateImage(cvSize(destination->width, destination->height),IPL_DEPTH_8U,1);
cvCvtColor(destination,destinationForGS,CV_RGB2GRAY);
}
How now to cut that image into images of size 10x10 pixels and iterate true them?
(width and height may not divide on 10 but if there would be some loss (like loss from 1*h to 9*h+9*h pixels per image) it would be OK for me. )
BTW can you output one of 10*10 images onto screen. please.
You can crop your images into small pieces like this (iteration not tested):
// source image
IplImage *source = cvLoadImage("lena.jpg", 1);
int roiSize = 10;
for(int j = 0; j < source->width/roiSize; ++j) {
for(int i = 0; i < source->height/roiSize; ++i) {
cvSetImageROI(source, cvRect(i*roiSize, j*roiSize, roiSize, roiSize));
// cropped image
IplImage *cropSource = cvCreateImage(cvGetSize(source), source->depth, source->nChannels);
// copy
cvCopy(source, cropSource, NULL);
// ... do what you want with your cropped image ...
// always reset the ROI
cvResetImageROI(source);
}
}
I think the simplest solution is to use Regions of Interest. Here is sample
/* load image */
IplImage *img1 = cvLoadImage("elvita.jpg", 1);
/* sets the Region of Interest
Note that the rectangle area has to be __INSIDE__ the image
You just iterate througt x and y.
*/
cvSetImageROI(img1, cvRect(x*10, y*10, x*10 + 10, y*10 + 10));
/* create destination image
Note that cvGetSize will return the width and the height of ROI */
IplImage *img2 = cvCreateImage(cvGetSize(img1),
img1->depth,
img1->nChannels);
/* copy subimage */
cvCopy(img1, img2, NULL);
/* always reset the Region of Interest */
cvResetImageROI(img1);

Resources