WPF WriteableBitmap problems with transparency - wpf

First of all Ill explain what I try to do, just in the case that someone comes up with a better approach
I need to blend too images using the "color" stile from photoshop (you know, the blending methods: Screen, hard light, color ... )
So, I have my base image (a png) and WriteableBitmap generated on execution time (lets call it color mask). Then I need to blend this two images using the "color" method and show the result in a UI component.
So far what Im trying is just to draw things on the WriteableBitmap but I'm facing unexpected behavior with the alpha channel.
My code so far:
// variables declaration
WriteableBitmap img = new WriteableBitmap(width, height, 96,96,PixelFormats.Bgra32,null);
pixels = new uint[width * height];
//function for setting the color of one pixel
private void SetPixel(int x, int y, Color c)
{
int pixel = width * y + x;
int red = c.R;
int green = c.G;
int blue = c.B;
int alpha = c.A;
pixels[pixel] = (uint)((blue << 24) + (green << 16) + (red << 8) + alpha);
}
//function for paint all the pixels of the image
private void Render()
{
Color c = new Color();
c.R = 255; c.G = 255; c.B = 255; c.A = 50;
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
SetPixel(x, y, c);
img.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
image1.Source = img; // image1 is a WPF Image in my XAML
}
Whenever I run the code with the color c.A = 255 I get the expected results. The whole Image is set to the desired color. But if I set c.A to a different value I get weird things.
If I set the color to BRGA = 0,0,255,50 I get a dark blue almost black. If I set it to BRGA = 255,255,255,50 I get a yellow ...
Any clue !?!?!
Thanks in advance !

Change the order of your colour components to
pixels[pixel] = (uint)((alpha << 24) + (red << 16) + (green << 8) + blue);

Related

Java: Converting RGB to ARGB to be used in BufferImage setRGB

I'm trying to make a dithering effect to just mess around with in my free time to hopefully learn more about java interfacing. i found out how to convert the 32 bit ARGB int which you get when using the .getRGB(x,y) for a BufferedImage and did the calculations to change the color to the red green and blue values that i would need. Now all I have to do is turn these red green and blue float values into an ARGB int again to be used in the setRGB(x,y,rgb) method. Thanks!
private static void dither(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++) {
int rgb = bi.getRGB(x, y);
float red = (rgb >> 16) & 0x000000FF;
float green = (rgb >>8 ) & 0x000000FF;
float blue = (rgb) & 0x000000FF;
red = Math.round(red / 255) * 255;
green = Math.round(green / 255) * 255;
blue = Math.round(blue / 255) * 255;
bi.setRGB(x, y, rgb); //this is where i need the red, green, blue values to be a single int
}
}
}
I'm thinking maybe I'd have to do the opposite of what i did to get the individual red, green and blue values but I'm not sure.
Please note I am still VERY new to coding and so please feel free to give me feedback on naming conventions and syntax.

Detecting and displaying number of players detected using Kinect

I'm trying to display number of players detected by Kinect sensor using an WPF application. In addition to displaying number of player I have also coloured the pixels based on their distance from the Kinect. Original goal was to measure the distance of the pixels and display the distance but I would also like to display how many people are in the frame. Here is the code snippets that I'm using now.
PS I have borrowed the idea from THIS tutorial and I'm using SDK 1.8 with XBOX 360 Kinect (1414)
private void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame==null)
{
return;
}
byte[] pixels = GenerateColoredBytes(depthFrame);
int stride = depthFrame.Width * 4;
image.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height,
96, 96, PixelFormats.Bgr32, null, pixels, stride);
}
}
private byte[] GenerateColoredBytes(DepthImageFrame depthFrame)
{
//get the raw data from kinect with the depth for every pixel
short[] rawDepthData = new short[depthFrame.PixelDataLength];
depthFrame.CopyPixelDataTo(rawDepthData);
/*
Use depthFrame to create the image to display on screen
depthFrame contains color information for all pixels in image
*/
//Height * Width *4 (Red, Green, Blue, Empty byte)
Byte[] pixels = new byte[depthFrame.Height * depthFrame.Width * 4];
//Hardcoded loactions for Blue, Green, Red (BGR) index positions
const int BlueIndex = 0;
const int GreenIndex = 1;
const int RedIndex = 2;
//Looping through all distances and picking a RGB colour based on distance
for (int depthIndex = 0, colorIndex = 0;
depthIndex < rawDepthData.Length &&
colorIndex<pixels.Length; depthIndex++, colorIndex+=4)
{
//Getting player
int player = rawDepthData[depthIndex] & DepthImageFrame.PlayerIndexBitmask;
//Getting depth value
int depth =rawDepthData[depthIndex]>>DepthImageFrame.PlayerIndexBitmaskWidth;
//.9M or 2.95'
if (depth <=900 )
{
//Close distance
pixels[colorIndex + BlueIndex] = 0;
pixels[colorIndex + GreenIndex] = 0;
pixels[colorIndex + RedIndex] = 255;
//textBox.Text = "Close Object";
}
//.9M - 2M OR 2.95' - 6.56'
else if (depth >900 && depth<2000)
{
//Bit further away
pixels[colorIndex + BlueIndex] = 255;
pixels[colorIndex + GreenIndex] = 0;
pixels[colorIndex + RedIndex] = 0;
}
else if (depth > 2000)
{
//Far away
pixels[colorIndex + BlueIndex] = 0;
pixels[colorIndex + GreenIndex] = 255;
pixels[colorIndex + RedIndex] = 0;
}
//Coloring all people in Gold
if (player > 0)
{
pixels[colorIndex + BlueIndex] = Colors.Gold.B;
pixels[colorIndex + GreenIndex] = Colors.Gold.G;
pixels[colorIndex + RedIndex] = Colors.Gold.R;
playersValue.Text = player.ToString();
}
}
return pixels;
}
Current goal is to--
Detect total number of players detected and display them in a textBox
Colour them according to the distance logic i.e depth <=900 is red.
With current code I can detect player and color them in Gold but as soon as a player is detected the image freezes and when the player is out of the frame the image unfreezes and acts normal. Is it because of the loop?
Ideas, guidance, recommendation and criticism all are welcome.
Thanks!
Screenshots:
Get a static variable inside your form code
Then set this variable using your video frame routine (dont define it there).
And then update the textbox view, probaply in your _sensor_AllFramesReady
As the arrival of new frames runs in a different thread
I dont see all code maybe to update call textbox.show
the main loop looks a bit strange though, too complex.
basicly you use it to color every pixel in your image.
as the kinect360 has 320x240 pixels so that makes a depth array of size 76800
You might simply create 2 for next loops loops for X and Y and then inside this loop have a variable increase to pick the proper depth value.

Skin Color Detection in OpenCV

I trying to do skin color detection in Opencv.
1) First i converted the image into HSV from RGB
cvCvtColor(frame, hsv, CV_BGR2HSV);
2) Than i had applied skin color threshold in the HSV image
cvInRangeS(hsv, hsv_min, hsv_max, mask); // hsv_min & hsv_max are the value for skin detection
3) So it generates the mash which has only skin color but in Black & white image, so i converted that image in to RGB
cvCvtColor(mask, temp, CV_GRAY2RGB);
4) so now i want the skin color in only RGB value.
for(c = 0; c < frame -> height; c++) {
uchar* ptr = (uchar*) ((frame->imageData) + (c * frame->widthStep));
uchar* ptr2 = (uchar*) ((temp->imageData) + (c * temp->widthStep));
for(d = 0; d < frame -> width; d++) {
if(ptr2[3*d+0] != 255 && ptr2[3*d+1] != 255 && ptr2[3*d+2] != 255 && ptr2[3*d+3] != 255 ){
ptr[3 * d + 0] = 0;
ptr[3 * d + 1] = 0;
ptr[3 * d + 2] = 0;
ptr[3 * d + 3] = 0;
}
}
}
now i am not getting the image that i want actually that has only skin color in RGB.
Any Solution,
Thanks
1st Original Image
2nd Skin Detected Image in Black & White
3rd Output (Not Actual)
you're already quite close.
given, you have a 3 channel mask already:
Mat mask, temp;
cv::cvtColor(mask, temp, CV_GRAY2RGB);
all you need to do is combine it with your original image to mask out all non-skin color:
(and no, don't write [error prone] loops there, better rely on the builtin functionality !)
Mat draw = frame & temp; // short for bitwise_and()
imshow("skin",draw);
waitKey();
Alternatively, without having to convert mask to RGB, you could .copyTo() passing the mask parameter
cv::cvtColor(inputFrame, hsv, CV_BGR2HSV);
cv::inRange(hsv, hsv_min, hsv_max, mask);
cv::Mat outputFrame;
inputFrame.copyTo(outputFrame, mask);

How to draw a zigzag line?

I am creating a document based application and i want to draw a horizontal line underlying the text. But, line should not be straight. i want to draw a line like this.
Currently i am using System.Graphics object to draw any object.
private void DrawLine(Graphics g, Point Location, int iWidth)
{
iWidth = Convert.ToInt16(iWidth / 2);
iWidth = iWidth * 2;
Point[] pArray = new Point[Convert.ToInt16(iWidth / 2)];
int iNag = 2;
for (int i = 0; i < iWidth; i+=2)
{
pArray[(i / 2)] = new Point(Location.X + i , Location.Y + iNag);
if (iNag == 0)
iNag = 2;
else
iNag = 0;
}
g.DrawLines(Pens.Black, pArray);
}
UPDATED:
Above code is working fine and line draws perfectly but, this code effects on application performance. Is there another way to do this thing.
If you want fast drawing just make a png image of the line you want, with width larger than you need and then draw the image:
private void DrawLine(Graphics g, Point Location, int iWidth)
{
Rectangle srcRect = new Rectangle(0, 0, iWidth, zigzagLine.Height);
Rectangle dstRect = new Rectangle(Location.X, Location.Y, iWidth, zigzagLine.Height);
g.DrawImage(zigzagLine, dstRect, srcRect, GraphicsUnit.Pixel);
}
zigzagLine is the bitmap.
valter

How to copy some part of WriteableBitmap?

I have some WriteableBitmap object.
Lets say that the image that is actully on the WriteableBitmap object is 600x400.
I want to copy part of the image - some Rectangle ( for example Rectangle of 100x100 in the middle of the WriteableBitmap ) and paste the copy to some other image control.
How can i do it ?
I suspect you've got this fixed now, but I had the same problem and I found the answer so I thought I'd post it. The code at http://writeablebitmapex.codeplex.com/ has a "Crop" routine that does pretty much what you're after. Once you have a SizeOfArgb constant set to 4, you can use this:
public static WriteableBitmap Crop(this WriteableBitmap bmp, int x, int y, int width, int height)
{
var srcWidth = bmp.PixelWidth;
var srcHeight = bmp.PixelHeight;
// If the rectangle is completly out of the bitmap
if (x > srcWidth || y > srcHeight)
{
return new WriteableBitmap(0, 0);
}
// Clamp to boundaries
if (x < 0) x = 0;
if (x + width > srcWidth) width = srcWidth - x;
if (y < 0) y = 0;
if (y + height > srcHeight) height = srcHeight - y;
// Copy the pixels line by line using fast BlockCopy
var result = new WriteableBitmap(width, height);
for (var line = 0; line < height; line++)
{
var srcOff = ((y + line) * srcWidth + x) * SizeOfArgb;
var dstOff = line * width * SizeOfArgb;
Buffer.BlockCopy(bmp.Pixels, srcOff, result.Pixels, dstOff, width * SizeOfArgb);
}
return result;
}
public static BitmapSource Crop(this BitmapSource bmp, Int32Rect rect)
{
return new CroppedBitmap(bmp, rect);
}

Resources