I read the "C.Sharp 3.0 in a Nutshell" book and met the next piece of code, that interested me.
unsafe void RedFilter(int[,] bitmap)
{
int length = bitmap.Length;
fixed (int* b = bitmap)
{
int* p = b;
for(int i = 0; i < length; i++)
*p++ &= 0xFF;
}
}
Could anyone explain me how does this "*p++ &= 0xFF" work?
The function is presumably meant to take a bitmap image, and filter out all the colors except red.
This assumes that it's a 32-bit bitmap, where each pixel is represented by an int.
You're dereferencing the memory location currently pointed to by p (which is an int), and ANDing it with 0xFF, which effectively leaves only the red component of the pixel (assuming that the lowest byte is the red component). You're also automatically incrementing the pointer to the next int (with ++). Does that answer it?
It's the same as this (IMO the original *p++ &= 0xFF; trick is a little nasty -- it's one line of code that's doing two things):
*p = *p & 0xFF;
p++;
An expression like a = a & 0xFF sets all but the bottom 8 bits of variable a to zero.
It's the kind of syntax you'd find in the C language, frowned upon there as well but not uncommon. Written out:
int temp = *p;
temp = temp & 0x000000ff;
*p = temp;
p = p + 1; // Move pointer by 4 bytes.
It depends on the bitmap format if this will work out well. Not commonly, the code resets the alpha of the pixels to zero. Producing a black image.
This code increments the pointer p, making it point to the next pixel in the bitmap, then masks off everything but the least significant byte, which, in Microsoft BMP format (and I assume in other nonstandard implementations) is in BGR format.
This has the effect of removing all of the color components except for red.
As you probably know,
x &= y
is the same as
x = x & y
An 'int' anded with '0xff' will set all the bits in the higher 3 bytes to zero (a mask).
The askterisk is dereferencing the pointer, so
*p
is an integer.
The 'post increment' updates the actual pointer value to point to the next integer in memory.
So in total, the code will run through 'length' integers in memory, and mask out all but the lowest byte (i.e., the 'red' byte if these are [A]BGR colour values).
Related
I am trying to increase the red value of an image by fifty percent. Here is my code:
public static Bitmap IncreaseRedFiftyPercent(Bitmap b)
{
Bitmap temp = (Bitmap) b;
Bitmap bmap = (Bitmap)temp.Clone();
Color c;
for (int i = 0; i < bmap.Width; i++)
{
for (int j = 0; j < bmap.Height; j++)
{
c = bmap.GetPixel(i, j);
byte increase = c.R + c.R * 0.5; //This line gives error
bmap.SetPixel(i, j, Color.FromArgb(increase, c.G, c.B));
}
}
b = (Bitmap)bmap.Clone();
return b;
}
Here is what i do: I read all pixels of the picture, and increase the red value by fifty percent and keep blue and green the same. But the line
byte increase = c.R + c.R * 0.5; //This line gives error
gives me an error saying that
Cannot implicitly convert type 'double' to 'byte'. An explicit conversion exists (are you missing
a cast?)
And i cannot convert double to byte? It looks like sensible what i am doing, what is wrong here?
Thanks
Arithmetic in C# is performed by first determining which operator to use by choosing from a list of possible operators:
int * int --> int
long * long --> long
double * double --> double
and so on; that list is quite long.
In your case the best operator is double * double --> double, and so the byte is converted to double. This is lossless. But the result is a double; it might have a fractional part, and its magnitude might be larger than the largest possible byte. Converting back to byte is lossy. Therefore you are required to say "I guarantee that I really want to make this lossy conversion" by inserting a cast to byte.
Now, before you do so you should make sure that you are in fact doing the right thing! If the byte is already at, say, 200, then increasing it by 50% to the double 300.00 and then converting that back to a byte that can only be between 0 and 255 is likely to produce unexpected results. Think carefully before you insert that cast.
You could use this instead, although it won't account for overflow (any result over 255 will roll over to 0):
byte increase = (byte)(c.R + c.R / 2);
Note that I use /2 instead of *0.5 to use integer math instead of floating-point math. If you're processing lots of large images the performance difference could be significant.
Based on your requirement something like this may work:
byte increase = (byte)(Math.Min(c.R + c.R / 2 , 255));
The problem is that when you take a byte (eg c.R) and multiply by a double (eg 0.5) then the result is a double (because a byte may not have the precision to hold the result). You are then trying to assign this to a byte and as the error message says no implicit conversion exists so you have to explicitly convert it.
This can be done with something like
byte increase = (byte)(c.R + c.R * 0.5);
And I've been reminded by another answer that this won't check for overflow so if c.R is more than 170 then you will get overflow issues. To this end you will want to do something like D Stanley's Min technique.
I am printing the mono chorme bit map image on thermal printer where i am able to print the image but at rightmost, one vertical line is getting printed. (The line is from Top right to bottom right with nearly 2mm thick)
Bitmap image = new Bitmap(imagePath, false);
int imageDepth = System.Drawing.Bitmap.GetPixelFormatSize(image.PixelFormat);
Rectangle monoChromeBitmapRectangle = new Rectangle(0, 0, image.Width, image.Height);
BitmapData monoChromebmpData = null;
int stride = 0;
monoChromebmpData = image.LockBits(monoChromeBitmapRectangle, ImageLockMode.ReadOnly, resizedImage.PixelFormat);
IntPtr ptr = monoChromebmpData.Scan0;
stride = monoChromebmpData.Stride;
int numbytes = stride * image.Height;
byte[] bitmapFileData = new byte[numbytes];
Marshal.Copy(ptr, bitmapFileData, 0, numbytes);
image.UnlockBits(monoChromebmpData);
//Invert bitmap colors
for (int i = 0; i < bitmapFileData.Length; i++)
{
bitmapFileData[i] ^= 0xFF;
}
StringBuilder hexaDecimalImageDataString = new StringBuilder(bitmapFileData.Length * 2);
foreach (byte b in bitmapFileData)
hexaDecimalImageDataString.AppendFormat("{0:X2}", b);
return hexaDecimalImageDataString;
Here i am converting the mono chrome bitmap image to byte array and from byte array to hexadecimal string.
i googled in forums but this kind of error is not discussed. (May be i am doing silly mistake)
Can any one suggest where exactly i am making the mistake.
Thanks in advance.
Cheers,
Siva.
Your are returning monoChromebmpData.Stride * image.Height bytes, i.e. each line in the image will be exactly monoChromebmpData.Stride * 8 pixels wide - but probably the original image has a pixel width that is less than that, hence the extra vertical line on the right.
Try something like this:
byte[] masks = new byte[]{0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
int byteWidth = (image.Width+7)/8;
int nBits = imageWidth % 8;
byte[] actualBitmapFileData = new byte[byteWidth*image.Height];
int yFrom = 0;
for (int y=0; y<image.Height; y++) {
for (int x=0; x<byteWidth-1; x++) {
actualBitmapFileData[y*byteWidth + x] = (bitmapFileData[yFrom + x] ^ 0xFF);
}
int lastX = byteWidth - 1;
actualBitmapFileData[y*byteWidth + lastX] = (bitmapFileData[yFrom + lastX] ^ 0xFF) & masks[nBits];
yFrom += stride;
}
it creates an actualBitmapFileData array for bitmapFileData with of the correct size.
Note that the last byte of every line would contain only nBits pixels - and so needs to be 'masked' to clear out the extra bit not corresponding with any pixel. This is done by & masks[nBits], where masks is an array of 8 bytes with the 8 masks to use. The actual values of the mask depend on how the printer works: you might need to set the extra bits to 0 or to 1, and the extra bits can be the most-significant or the least-significant ones. The mask values used above assume that the most significant bits are rendered to the right, and that the masked bits should be set to 0. Depending on how the printer works it might be necessary to swap the bits and/or set the masked bits to 1 instead than zero (complementing the mask and using | instead than &)
For performance reasons each horizontal row in a Bitmap is buffered to a DWORD boundary (see this answer for more details). So if your Bitmap's width multiplied by it's bits-per-pixel(bpp) is not divisible by 32 (DWORD = 32bits) then it's padded with extra bits. So a 238x40 1bpp Bitmap has a memory foot print of 8 DWORDs per row or 256 bits.
The BitmapData object's Stride property is the number of bytes that each row of your bitmap consumes in memory. When you capture the Byte Array, you're capturing that padding as well.
Before you convert the byte array to hex you need to trim the buffer off the end. The following function should do that nicely.
public static byte[] TruncatePadding(byte[] PaddedImage, int Width, int Stride, int BitsPerPixel)
{
//Stride values can be negative
Stride = Math.Abs(Stride);
//Get the actual number of bytes each row contains.
int shortStride = (int)Math.Ceiling((double)(Width*BitsPerPixel/8));
//Figure out the height of the image from the array data
int height = PaddedImage.Length / Stride;
if (height < 1)
return null;
//Allocate the new array based on the image width
byte[] truncatedImage = new byte[shortStride * height];
//Copy the data minus the padding to a new array
for(int i = 0; i < height; i++)
Buffer.BlockCopy(PaddedImage,i*Stride,truncatedImage,i*shortStride,shortStride);
return truncatedImage;
}
The comments from MiMo and MyItchyChin helped me alot on resolving the issue.
The problem is getting the extra line at the end. So technically, on printing the each row of image, last few byte information is incorrect.
The reason for getting this problem is, the image size could be anything, but whne it sends to printer, the byte width should be divisible by eight. In my case my printer expects the bytewidth as input so i must be careful on passing the image.
Assume i have image 168x168 size.
byteWidth = Math.Ceiling(bitmapDataWidth / 8.0);
so the byteWidth is 21 here, As per printer expectation i did Left shift operation to 24 which is diviseble by 8, so virtually i increased the size of image by 3bytes and then started reading the byte information. The line i am talking about is that extra 3 bytes. Since no data is there, the black line is getting printed.
I wrote the logic in such a way, where byte array doesnot effect with shift operations hence it worked for me.
Early days for me in image processing, So please ignore, if i made a silly mistake and explaining the solution here.
I've been working on an edge detection program in C#, and to make it run faster, I recently made it use lock bits. However, lockBits is still not as fast as I would like it to run. Although the problem could be my general algorithm, I'm also wondering if there is anything better than lockBits I can use for image processing.
In case the problem is the algorithm, here's a basic explanation. Go through an array of Colors (made using lockbits, which represent pixels) and for each Color, check the color of the eight pixels around that pixel. If those pixels do not match the current pixel closely enough, consider the current pixel an edge.
Here's the basic code that defines if a pixel is an edge. It takes in a Color[] of nine colors, the first of which is the pixel is to check.
public Boolean isEdgeOptimized(Color[] colors)
{
//colors[0] should be the checking pixel
Boolean returnBool = true;
float percentage = percentageInt; //the percentage used is set
//equal to the global variable percentageInt
if (isMatching(colors[0], colors[1], percentage) &&
isMatching(colors[0], colors[2], percentage) &&
isMatching(colors[0], colors[3], percentage) &&
isMatching(colors[0], colors[4], percentage) &&
isMatching(colors[0], colors[5], percentage) &&
isMatching(colors[0], colors[6], percentage) &&
isMatching(colors[0], colors[7], percentage) &&
isMatching(colors[0], colors[8], percentage))
{
returnBool = false;
}
return returnBool;
}
This code is applied for every pixel, the colors of which are fetched using lockbits.
So basically, the question is, how can I get my program to run faster? Is it my algorithm, or is there something I can use that is faster than lockBits?
By the way, the project is on gitHub, here
Are you really passing in a floating point number as a percentage to isMatching?
I looked at your code for isMatching on GitHub and well, yikes. You ported this from Java, right? C# uses bool not Boolean and while I don't know for sure, I don't like the looks of code that does that much boxing and unboxing. Further, you're doing a ton of floating point multiplication and comparison when you don't need to:
public static bool IsMatching(Color a, Color b, int percent)
{
//this method is used to identify whether two pixels,
//of color a and b match, as in they can be considered
//a solid color based on the acceptance value (percent)
int thresh = (int)(percent * 255);
return Math.Abs(a.R - b.R) < thresh &&
Math.Abs(a.G - b.G) < thresh &&
Math.Abs(a.B - b.B) < thresh;
}
This will cut down the amount of work you're doing per pixel. I still don't like it because I try to avoid method calls in the middle of a per-pixel loop especially an 8x per-pixel loop. I made the method static to cut down on an instance being passed in that isn't used. These changes alone will probably double your performance since we're doing only 1 multiply, no boxing, and are now using the inherent short-circuit of && to cut down the work.
If I were doing this, I'd be more likely to do something like this:
// assert: bitmap.Height > 2 && bitmap.Width > 2
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int scaledPercent = percent * 255;
unsafe {
byte* prevLine = (byte*)data.Scan0;
byte* currLine = prevLine + data.Stride;
byte* nextLine = currLine + data.Stride;
for (int y=1; y < bitmap.Height - 1; y++) {
byte* pp = prevLine + 3;
byte* cp = currLine + 3;
byte* np = nextLine + 3;
for (int x = 1; x < bitmap.Width - 1; x++) {
if (IsEdgeOptimized(pp, cp, np, scaledPercent))
{
// do what you need to do
}
pp += 3; cp += 3; np += 3;
}
prevLine = currLine;
currLine = nextLine;
nextLine += data.Stride;
}
}
private unsafe static bool IsEdgeOptimized(byte* pp, byte* cp, byte* np, int scaledPecent)
{
return IsMatching(cp, pp - 3, scaledPercent) &&
IsMatching(cp, pp, scaledPercent) &&
IsMatching(cp, pp + 3, scaledPercent) &&
IsMatching(cp, cp - 3, scaledPercent) &&
IsMatching(cp, cp + 3, scaledPercent) &&
IsMatching(cp, np - 3, scaledPercent) &&
IsMatching(cp, np, scaledPercent) &&
IsMatching(cp, np + 3, scaledPercent);
}
private unsafe static bool IsMatching(byte* p1, byte* p2, int thresh)
{
return Math.Abs(p1++ - p2++) < thresh &&
Math.Abs(p1++ - p2++) < thresh &&
Math.Abs(p1 - p2) < thresh;
}
Which now does all kinds of horrible pointer mangling to cut down on array accesses and so on. If all of this pointer work makes you feel uncomfortable, you can allocate byte arrays for prevLine, currLine and nextLine and do a Marshal.Copy for each row as you go.
The algorithm is this: start one pixel in from the top and left and iterate over every pixel in the image except the outside edge (no edge conditions! Yay!). I keep pointers to the starts of each line, prevLine, currLine, and nextLine. Then when I start the x loop, I make up pp, cp, np which are previous pixel, current pixel and next pixel. current pixel is really the one we care about. pp is the pixel directly above it, np directly below it. I pass those into IsEdgeOptimized which looks around cp, calling IsMatching for each.
Now this all assume 24 bits per pixel. If you're looking at 32 bits per pixel, all those magic 3's in there need to be 4's, but other than that the code doesn't change. You could parameterize the number of bytes per pixel if you want so it could handle either.
FYI, the channels in the pixels are typically b, g, r, (a).
Colors are stored as bytes in memory. Your actual Bitmap, if it is a 24 bit image is stored as a block of bytes. Scanlines are data.Stride bytes wide, which is at least as large as 3 * the number of pixels in a row (it may be larger because scan lines are often padded).
When I declare a variable of type byte * in C#, I'm doing a few things. First, I'm saying that this variable contains the address of a location of a byte in memory. Second, I'm saying that I'm about to violate all the safety measures in .NET because I could now read and write any byte in memory, which can be dangerous.
So when I have something like:
Math.Abs(*p1++ - *p2++) < thresh
What it says is (and this will be long):
Take the byte that p1 points to and hold onto it
Add 1 to p1 (this is the ++ - it makes the pointer point to the next byte)
Take the byte that p2 points to and hold onto it
Add 1 to p2
Subtract step 3 from step 1
Pass that to Math.Abs.
The reasoning behind this is that, historically, reading the contents of a byte and moving forward is a very common operation and one that many CPUs build into a single operation of a couple instructions that pipeline into a single cycle or so.
When we enter IsMatching, p1 points to pixel 1, p2 points to pixel 2 and in memory they are laid out like this:
p1 : B
p1 + 1: G
p1 + 2: R
p2 : B
p2 + 1: G
p2 + 2: R
So IsMatching just does the the absolute difference while stepping through memory.
Your follow-on question tells me that you don't really understand pointers. That's OK - you can probably learn them. Honestly, the concepts really aren't that hard, but the problem with them is that without a lot of experience, you are quite likely to shoot yourself in the foot, and perhaps you should consider just using a profiling tool on your code and cooling down the worst hot spots and call it good.
For example, you'll note that I look from the first row to the penultimate row and the first column to the penultimate column. This is intentional to avoid having to handle the case of "I can't read above the 0th line", which eliminates a big class of potential bugs which would involve reading outside a legal memory block, which may be benign under many runtime conditions.
Instead of copying each image to a byte[], then copying to a Color[], creating another temp Color[9] for each pixel, and then using SetPixel to set the color, compile using the /unsafe flag, mark the method as unsafe, replace copying to a byte[] with Marshal.Copy to:
using (byte* bytePtr = ptr)
{
//code goes here
}
Make sure you replace the SetPixel call with setting the proper bytes. This isn't an issue with LockBits, you need LockBits, the issue is that you're being inefficient with everything else related to processing the image.
If you want to use parallel task execution, you can use the Parallel class in System.Threading.Tasks namespace. Following link has some samples and explanations.
http://csharpexamples.com/fast-image-processing-c/
http://msdn.microsoft.com/en-us/library/dd460713%28v=vs.110%29.aspx
You can split the image into 10 bitmaps and process each one, then finally combine them (just an idea).
I have a problem regarding some pixel-based operations in C#.
I wrote a class that serves as an image shell around a Bitmap. It can give you the RGB values of a pixel at a certain (x,y) location in the image much faster than the Bitmap.GetRGB(x,y) color object by using BitmapData and LockBits to get direct access to the image array and read the bytes from there. I added this function to get the RGB in an 0x00RRGGBB mask at a (x,y) pixel.
public unsafe int getPixel(int x, int y)
{
byte* imgPointer = (byte*)bmpData.Scan0;
int pixelPos = 0;
if (y > 0) pixelPos += (y * bmpData.Stride);
pixelPos += x * (hasAlpha ? 4 : 3);
int blue = *(imgPointer + pixelPos);
int green = *(imgPointer + pixelPos + 1);
int red = *(imgPointer + pixelPos + 2);
int rgb = red << 16;
rgb += green << 8;
rgb += blue;
return rgb;
}
This works flawlessly for all the images I've worked with thus far, except for any image I generate using MSPaint. For example, I made a 5x1 image in paint containing 5 shades of yellow. When I load this image into my program however, the image stride is 16! I suspected it to be 15 (3 bytes per pixel, 5 pixels) but for some reason after the first three bytes (first pixel) there is an extra byte, and then the rest of the pixels follow in the array.
I have only found this for images that are saved by MSpaint and I was hoping anyone could explain me what that extra byte is for and how to detect that extra byte.
From MSDN:
The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
So stride is always a multiple of 4, and for your 3x5, will round up to 16.
Can anyone explain in a simple way the codes below:
public unsafe static float sample(){
int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
return *(float*)(&result); //don't know what for... please explain
}
Note: the above code uses unsafe function
For the above code, I'm having hard time because I don't understand what's the difference between its return value compare to the return value below:
return (float)(result);
Is it necessary to use unsafe function if your returning *(float*)(&result)?
On .NET a float is represented using an IEEE binary32 single precision floating number stored using 32 bits. Apparently the code constructs this number by assembling the bits into an int and then casts it to a float using unsafe. The cast is what in C++ terms is called a reinterpret_cast where no conversion is done when the cast is performed - the bits are just reinterpreted as a new type.
The number assembled is 4019999A in hexadecimal or 01000000 00011001 10011001 10011010 in binary:
The sign bit is 0 (it is a positive number).
The exponent bits are 10000000 (or 128) resulting in the exponent 128 - 127 = 1 (the fraction is multiplied by 2^1 = 2).
The fraction bits are 00110011001100110011010 which, if nothing else, almost have a recognizable pattern of zeros and ones.
The float returned has the exact same bits as 2.4 converted to floating point and the entire function can simply be replaced by the literal 2.4f.
The final zero that sort of "breaks the bit pattern" of the fraction is there perhaps to make the float match something that can be written using a floating point literal?
So what is the difference between a regular cast and this weird "unsafe cast"?
Assume the following code:
int result = 0x4019999A // 1075419546
float normalCast = (float) result;
float unsafeCast = *(float*) &result; // Only possible in an unsafe context
The first cast takes the integer 1075419546 and converts it to its floating point representation, e.g. 1075419546f. This involves computing the sign, exponent and fraction bits required to represent the original integer as a floating point number. This is a non-trivial computation that has to be done.
The second cast is more sinister (and can only be performed in an unsafe context). The &result takes the address of result returning a pointer to the location where the integer 1075419546 is stored. The pointer dereferencing operator * can then be used to retrieve the value pointed to by the pointer. Using *&result will retrieve the integer stored at the location however by first casting the pointer to a float* (a pointer to a float) a float is instead retrieved from the memory location resulting in the float 2.4f being assigned to unsafeCast. So the narrative of *(float*) &result is give me a pointer to result and assume the pointer is pointer to a float and retrieve the value pointed to by the pointer.
As opposed to the first cast the second cast doesn't require any computations. It just shoves the 32 bit stored in result into unsafeCast (which fortunately also is 32 bit).
In general performing a cast like that can fail in many ways but by using unsafe you are telling the compiler that you know what you are doing.
If i'm interpreting what the method is doing correctly, this is a safe equivalent:
public static float sample() {
int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
byte[] data = BitConverter.GetBytes(result);
return BitConverter.ToSingle(data, 0);
}
As has been said already, it is re-interpreting the int value as a float.
This looks like an optimization attempt. Instead of doing floating point calculations you are doing integer calculations on the Integer representation of a floating point number.
Remember, floats are stored as binary values just like ints.
After the calculation is done you are using pointers and casting to convert the integer into the float value.
This is not the same as casting the value to a float. That will turn the int value 1 into the float 1.0. In this case you turn the int value into the floating point number described by the binary value stored in the int.
It's quite hard to explain properly. I will look for an example. :-)
Edit:
Look here: http://en.wikipedia.org/wiki/Fast_inverse_square_root
Your code is basically doing the same as described in this article.
Re : What is it doing?
It is taking the value of the bytes stored int and instead interpreting these bytes as a float (without conversion).
Fortunately, floats and ints have the same data size of 4 bytes.
Because Sarge Borsch asked, here's the 'Union' equivalent:
[StructLayout(LayoutKind.Explicit)]
struct ByteFloatUnion {
[FieldOffset(0)] internal byte byte0;
[FieldOffset(1)] internal byte byte1;
[FieldOffset(2)] internal byte byte2;
[FieldOffset(3)] internal byte byte3;
[FieldOffset(0)] internal float single;
}
public static float sample() {
ByteFloatUnion result;
result.single = 0f;
result.byte0 = 154;
result.byte1 = 153;
result.byte2 = 25;
result.byte3 = 64;
return result.single;
}
As others have already described, it's treating the bytes of an int as if they were a float.
You might get the same result without using unsafe code like this:
public static float sample()
{
int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
return BitConverter.ToSingle(BitConverter.GetBytes(result), 0);
}
But then it won't be very fast any more and you might as well use floats/doubles and the Math functions.