void draw(unsigned char *image)
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
if (someCondition)
{
int red = x * 256 / WIDTH;
int green = 255;
int blue = y * 256 / HEIGHT;
image[0] = (unsigned char)blue;
image[1] = (unsigned char)green;
image[2] = (unsigned char)red;
}
else
{
image[0] = 0;
image[1] = 0;
image[2] = 0;
}
image += 3;
}
}
}
What does incrementing image+=3; actually do here. I'm trying to convert the same c++ code to C#, but unable to achieve this. I'm using byte[] image in C#, now how should I do image+=3 in C#. Is it scaling the image?
From the code it is evident that the pointer points to an element of an array of unsigned char:
[ ][ ][ ][ ] ........... [ ]
^
|
image
Next consider that image[i] is equivalent (really equivalent, that is how it is defined) to *(image + i), ie it increments the pointer by i and dereferences it. You can write image[0] to get the element image points to. You can type image[1] to get the next element in the array.
Lets call the actual array x then you can access its elements via incrementing image like this:
x[0] x[1] x[2] x[3] x[4] x[5]
image[0] image[1] image[2]
(image+3)[0] (image+3)[1] (image+3)[2]
In other words, the author could have used some offset in the outer loop which increments by 3 in each iteration and then instead of image[ i ] they would have used image[ i + offset ]. Instead they choose to increment image which has the same effect.
Here is your code in C# with comments which hopefully help understand what is done.
I highly recommend reading this article about image strides.
I read in the comments that each pixel has 3-byte which is why it is incremented by 3... while this might be true for some images, it is overall wrong. The bytes per pixel are depended on the pixel format of the image. you image can have 1-byte per pixel, 2-byte per pixel, 3-byte per pixel, 4-byte per pixel. The byte per pixel are also known as Color depth.
using System;
using System.Linq;
using System.Drawing;
using System.Drawing.Imaging;
namespace something
{
void draw(Bitmap bmp)
{
BitmapData data = null;
try {
// Returns an object of type BitmapData.
// BitmapData object grants you access
// to the address of the first pixel.
data = bmp.UnlockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite,
bmp.PixelFormat);
unsafe {
// Byte per pixel.
// This is really import!
// By checking how many bytes a pixel consumes
// you know how to increment your raw pixel data.
int bpp = Bitmap.GetPixelFormatSize(data.PixelFormat) / 8;
// Pointer to the first pixel.
byte* ptFirst = (byte*)data.Scan0;
// Using a parallel loop here
// drastically improves performance.
Parallel.For(0, data.Height, y =>
{
// Get the pointer of the first pixel
// in the current stride.
// If you imagine your image as a table with
// rows and columns, then this is the 'index'
// of the row.
// Images are built from multiple strides (rows).
byte* pixel = ptFirst + (y * data.Stride);
// IMPORTANT: Incrementing by byte-per-pixel
// is crucial here as you need to skip n-bytes
// to get to the next pixel.
// The pixel count per stride is the
// width multiplied by byte-per-pixel.
for (int x=0; x<data.Stride; x+=bpp)
{
if (someCondition) {
// Calc some colour values.
byte r = (byte)(x*256/data.Width);
byte g = byte.MaxValue;
byte b = (byte)(y*256/data.Height);
// Assign colour.
pixel[x+2]=r;
pixel[x+1]=g;
pixel[x+0]=b;
}
else {
// Set pixel to black.
pixel[x+2]=0;
pixel[x+1]=0;
pixel[x+0]=0;
}
}
}
}
}
finally {
if (null != data) {
bmp.UnlockBits(data);
}
}
}
}
Related
I am using OpenCV for android in my project to process a YUV420 (https://wiki.videolan.org/YUV/#NV12) image. As the rest of the project is in C#, I am using GCHandles to copy an array of bytes to the C++ code. I have made sure that the data are OK in C++ by making a sum of all the bytes both in C# and C++ and comparing them. However, when I try this:
int foo(unsigned char * inputPtr, int width, int height) {
cv::InputArray input_image = cv::Mat(height + height /2, width, CV_8UC1, inputPtr);
int res = 0;
for (int y = 0; y < input_image.rows(); y++) {
for (int x = 0; x < input_image.cols(); x++) {
res += (int)input_image.getMat().ptr(x + y * input_image.cols());
}
}
return res;
}
, zero is returned every time (the C# count still returns correct numbers). The sum of all bytes that returns correct values looks like this:
int foo(unsigned char * inputPtr, int width, int height) {
int res = 0;
for (int i = 0; i < width * height * 1.5f; i++) {
res += (int)inputPtr[i];
}
return res;
}
The cv::Mat() arguments should be correct based on this question: Converting from YUV colour space to RGB using OpenCV
What reason could OpenCV have to decide not to create a matrix out of seemingly valid data?
EDIT: Forgot to add that the inputPtr pointer points to a C# byte[] with the size of (int)(camBytes.Width * camBytes.Height * 1.5f).
Ptr return pointer but no value. Use at():
res += (int)input_image.getMat().at<uchar>(y, x);
I've tried to read a 32-bit grayscale tiff file which each pixel in the image contains a floating point number. But during the reading process, the buffer array contains 4 values for each pixel. For instance [ pixel value = 43.0 --> byte values for the pixel = {0 , 0 , 44 , 66}]. I can't understand the relation between float pixel value and the byte values. I also wrote the image using the buffer but pixel values for output image are int values like 1073872896. Any suggestion would be appreciated.
using (Tiff input = Tiff.Open(#"E:\Sample_04.tif", "r"))
{
// get properties to use in writing output image file
int width = input.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
int height = input.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
int samplesPerPixel = input.GetField(TiffTag.SAMPLESPERPIXEL)[0].ToInt();
int bitsPerSample = input.GetField(TiffTag.BITSPERSAMPLE)[0].ToInt();
int photo = input.GetField(TiffTag.PHOTOMETRIC)[0].ToInt();
int scanlineSize = input.ScanlineSize();
byte[][] buffer = new byte[height][];
for (int i = 0; i < height; i++)
{
buffer[i] = new byte[scanlineSize];
input.ReadScanline(buffer[i], i);
}
using (Tiff output = Tiff.Open("output.tif", "w"))
{
output.SetField(TiffTag.SAMPLESPERPIXEL, samplesPerPixel);
output.SetField(TiffTag.IMAGEWIDTH, width);
output.SetField(TiffTag.IMAGELENGTH, height);
output.SetField(TiffTag.BITSPERSAMPLE, bitsPerSample);
output.SetField(TiffTag.ROWSPERSTRIP, output.DefaultStripSize(0));
output.SetField(TiffTag.PHOTOMETRIC, photo);
output.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
output.SetField(TiffTag.COMPRESSION, compression);
int j = 0;
for (int i = 0; i < h; i++)
{
output.WriteScanline(buffer[i], j);
j++;
}
}
}
Update 1:
I found out the relation between four bytes and the pixel value using BitConverter class in c# that is like this:
byte[] a = { 0, 0, 44, 66 } --> 43 = BitConverter.ToSingle(a, 0) and 1110179840 = BitConverter.ToInt32(a, 0). It seem bytes are converted to int32 and now the question is how convert byte values to float?
Update 2:
The original tiff file and the tiff after writing the snippet code have been attached.Why is the output tiff file messed up?
I added this line of code to convert pixel values to floating number and it works fine.
output.SetField(TiffTag.SAMPLEFORMAT, SampleFormat.IEEEFP);
I have this code;
BitmapData bdBackground = Background.LockBits(new Rectangle(0, 0, Background.Width,
Background.Height), ImageLockMode.ReadWrite, Background.PixelFormat);
BitmapData bdForeground = videoFrame.LockBits(new Rectangle(0, 0, videoFrame.Width,
videoFrame.Height), ImageLockMode.ReadWrite, videoFrame.PixelFormat);
unsafe
{
for (int x = 0; x < videoFrame.Width; x++)
{
byte* columnBackground = (byte*)bdBackground.Scan0 + (x * bdBackground.Stride);
byte* columnForeground = (byte*)bdForeground.Scan0 + (x * bdForeground.Stride);
for (int y = 0; y < videoFrame.Height; y++)
{
if (columnBackground[x * pixelSize] == columnForeground[x * pixelSize])
{
columnForeground[x] = 0;
}
}
}
}
Background.UnlockBits(bdBackground);
videoFrame.UnlockBits(bdForeground);
it gives me error;
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
in if (columnBackground[x * pixelSize] == columnForeground[x * pixelSize])
what is the reason for that? I take this code from here
First, you need to understand how an image is stored in an array.
Images "usually in most APIs" are row major, meaning they are stored row by row (usually in a one dimensional array).
To loop through a row major image (walk the pixels), the outer loop is usually from 0 to height, and the inner from 0 to width. This makes the loops easier to read, and increases cache hits.
Stride is a very important concept, it represents the number of bytes needed for each row, and is not necessarily equal to the width*bytes per pixel, as padding for alignment reasons is usually present.
Stride is used to access a new row, for example, if I want to access the third row:
third_Row = 3 * image_stride;
If you want to access the 10th pixel of the third row, you just add (10 * bytes per pixel) to third_Row:
third_Row_Tenth_Pixel = 3 * image_stride + 10 * Bytes_per_pixel
NOTE: please mark the above does not apply to any image where bits per pixel are lower than 8, usually 4, 2, or 1 are used.
What you are doing is the reverse, you are multiplying the column number by the stride, instead of the row number, effectively, stepping out of the range of the image.
In short, reverse the x and y loops, making the y one contain the x one(for reasons of increasing cache hits):
unsafe
{
for (int y = 0; y < videoFrame.Height; y++)
{
byte* columnBackground = (byte*)bdBackground.Scan0 + (y * bdBackground.Stride);
byte* columnForeground = (byte*)bdForeground.Scan0 + (y * bdForeground.Stride);
for (int x = 0; x < videoFrame.Width; x++)
{
if (columnBackground[x * pixelSize] == columnForeground[x * pixelSize])
{
columnForeground[x] = 0;
}
}
}
}
Background.UnlockBits(bdBackground);
videoFrame.UnlockBits(bdForeground);
You never use the y variable when accessing the bitmap array. You should be multiplying y by the Stride instead of x. Then add x * pixelSize like you are doing.
What's the faster way to effectively fill an array of bytes where each byte represents a pixel (black or white: < 125 = black, > 125 = white) from a Bitmap class?
I used this for colored images: Better/faster way to fill a big array in C#
However now I'm looking for something different (I can even use a single color like Red to fill this, it doesn't matter is just something I should choose), because the array format changed.
Any suggestion? Actually I'm using this code, which is obviusly not the best idea
for (int x = 0; x < LgLcd.NativeConstants.LGLCD_BMP_WIDTH; ++x)
{
for (int y = 0; y < LgLcd.NativeConstants.LGLCD_BMP_HEIGHT; ++y)
{
tmp = bmp.GetPixel(x, y);
array[y * LgLcd.NativeConstants.LGLCD_BMP_WIDTH + x] = (byte)((tmp.R == 255 && tmp.G == 255 && tmp.B == 255) ? 0 : 255);
//array[y * x] = (byte)0;
}
}
My idea was parallelizing everything (yea, 1 thread per line maybe? (or per column)), it should help I think.
EDIT:
Ok, first, I need a way to have the possibility to access different bytes of the image at the same time, Brandon Moretz is suggesting maybe the correct way to access bytes with lockbits. I would like to avoid, however, unsafe code. Does Lockbits involves necessarily unsafe code?
Second, my idea of parallelization was to use Parallel.For. This method should use the ThreadPool class, which will use an amount of threads not greater than cores of your cpu, and they are pre-allocated.
This method will be called a lot of times, so I think it's not a big trouble, because the threadpool will be used a lot after first call.
Is what I'm saying correct?
Is using "unsafe" code blocks an option? You can use LockBits on a Bitmap to get it's BitmapData, then use Scan0 & Stride properties to iterate over it.
If it's 255 colors I'm assuming a byte per pixel, so so something like:
*( ( ( byte* )bmpData.Scan0 ) + ( y * bmpData.Stride ) + x ) = (byte)((tmp.R == 255 && tmp.G == 255 && tmp.B == 255) ? 0 : 255);
General approach is to divide the image into regions then process. i.e. you can use:
Thread 1) for (int x = 0; x < LGLCD_BMP_WIDTH /2; ++x) { ... }
Thread 2) for (int x = LGLCD_BMP_WIDTH / 2; x < LGLCD_BMP_WIDTH; ++x) { ... }
where you would have two halves of the image be processed by different threads. You can divide further into 4, 8, etc. pieces as you wish. A thread per line would be excess, as thread creation overhead would overwhelm the benefits by a large margin.
I found the answer by myself, working with lockbits and Marshal.ReadByte with a really nice and fast result:
public void SetPixels(Bitmap image)
{
byte[] array = Pixels;
var data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Parallel.For(0, data.Height, new Action<int>(i =>
{
byte tmp;
int pixel4bpp, pixelPerbpp;
pixelPerbpp = data.Stride / data.Width;
for (pixel4bpp = 0; pixel4bpp < data.Stride; pixel4bpp += pixelPerbpp)
{
tmp = (byte)((
Marshal.ReadByte(data.Scan0, 0 + (data.Stride * i) + pixel4bpp)
+ Marshal.ReadByte(data.Scan0, 1 + (data.Stride * i) + pixel4bpp)
+ Marshal.ReadByte(data.Scan0, 2 + (data.Stride * i) + pixel4bpp)
+ Marshal.ReadByte(data.Scan0, 3 + (data.Stride * i) + pixel4bpp)
) / pixelPerbpp);
array[i * data.Width + (pixel4bpp / pixelPerbpp)] = tmp;
}
}));
image.UnlockBits(data);
}
I'm trying to create a directshow graph to playback a video composed of 8bit grayscale bitmaps. (using directshow.net.)
I'm using a source filter and the vmr9 renderer.
The source filter's output pin is defined using the following code :
bmi.Size = Marshal.SizeOf(typeof(BitmapInfoHeader));
bmi.Width = width;
bmi.Height = height;;
bmi.Planes = 1;
bmi.BitCount = (short)bitcount;
bmi.Compression = 0;
bmi.ImageSize = Math.Abs(bmi.Height) * bmi.Width * bmi.BitCount / 8;
bmi.ClrUsed = bmi.BitCount <= 8 ? 256 : 0;
bmi.ClrImportant = 0;
//bmi.XPelsPerMeter = 0;
//bmi.YPelsPerMeter = 0;
bool isGrayScale = bmi.BitCount <= 8 ? true : false;
int formatSize = Marshal.SizeOf(typeof(BitmapInfoHeader));
if (isGrayScale == true)
{
MessageWriter.Log.WriteTrace("Playback is grayscale.");
/// Color table holds an array of 256 RGBQAD values
/// Those are relevant only for grayscale bitmaps
formatSize += Marshal.SizeOf(typeof(RGBQUAD)) * bmi.ClrUsed;
}
IntPtr ptr = Marshal.AllocHGlobal(formatSize);
Marshal.StructureToPtr(bmi, ptr, false);
if (isGrayScale == true)
{
/// Adjust the pointer to the beginning of the
/// ColorTable address and create the grayscale color table
IntPtr ptrNext = (IntPtr)((int)ptr + Marshal.SizeOf(typeof(BitmapInfoHeader)));
for (int i = 0; i < bmi.ClrUsed; i++)
{
RGBQUAD rgbCell = new RGBQUAD();
rgbCell.rgbBlue = rgbCell.rgbGreen = rgbCell.rgbRed = (byte)i;
rgbCell.rgbReserved = 0;
Marshal.StructureToPtr(rgbCell, ptrNext, false);
ptrNext = (IntPtr)((int)ptrNext + Marshal.SizeOf(typeof(RGBQUAD)));
}
}
This causes Renderstream to return "No combination of intermediate filters could be found to make the connection."
Please help!
Thanks.
to be honest, I've not seen any palette handling code for a little while. I'm not that surprised that it no longer works.
The standard way to define grey scale is using YUV with 0 bits for U and V. That takes the same space, but does not require a table lookup, since the Y bits are valid as they are. The standard FOURCC is 'Y800', with a guid created using FOURCCMap as the subtype. I don't know if the VMR will accept this directly, but if not, you could use the YUV transform from www.gdcl.co.uk to convert it to something acceptable, such as YUY2, by inserting zeros (YUY2 is widely accepted but double the space).
G