openCV: adding transparency to IplImage - opencv

I have a 3-channel IplImage. I would like to create a 4-channel image and set the alpha channel for it to a value less than 1.0 to make it semi-transparent.
First I set the alpha channel (the 4-th channel) to 0.5:
cvSet(Image_c4, cvScalar(0,0,0,0.5);
Here is the command that I used to copy the 3-channel image into a 4-channel image.
cvCvtColor(Image_c3, Image_c4, CV_RGB2RGBA);
The problem: Image_c3 is in color. Image_c4 becomes a gray scale copy of Image_c3 (and with no transparency).
Update:
It turned out that the code above is actually correct and works and is actually more concise than the suggested solutions in the answers below. I had an unrelated bug somewhere else.

Maybe there is another way but I add transparency like this:
// BGR split
cvSplit(im1_bgr, im1_b, im1_g, im1_r, NULL);
// Alpha channel creation (transparency)
IplImage *im1_a = cvCreateImage(cvGetSize(im1_bgr), 8, 1);
// Set the alpha value
cvSet(im1_a, cvScalar(128), NULL);
// Merge the 4 channel to an BGRA image
IplImage *im1_bgra = cvCreateImage(cvGetSize(im1_bgr), 8, 4);
cvMerge(im1_b, im1_g, im1_r, im1_a, im1_bgra);

//This code help to make a transparency image But it take src image as one //single color background see![Removing background and added black background color ][1]
Mat dst;//(src.rows,src.cols,CV_8UC4);
Mat tmp,alpha;
cvtColor(src,tmp,CV_BGR2GRAY);
threshold(tmp,alpha,0,255,THRESH_BINARY);
Mat rgb[3];
split(src,rgb);
Mat rgba[4]={rgb[0],rgb[1],rgb[2],alpha};
merge(rgba,4,dst);
imwrite("dst.png",dst);
//dst is transparency image see here![output image as transparency image][2]
[1]: http://i.stack.imgur.com/9THqs.png
[2]: http://i.stack.imgur.com/mpmgy.png

Related

Photoshop like brush with OpenCV

I am trying to add some blur brush stroke with OpenCV
If I use cv.add or cv.addweighted, I only got half of the red color (look pink),
but I want the red to cover the underlying picture, not blend.
If I use copyto or clone, I can't get the blur edge, so how should I do it ??
The background of your brush image is black. If you were in photoshop and set that brush layer's blend mode to screen the red gradient would show through and the black background would become transparent.
Here are a couple of relevant posts:
How does photoshop blend two images together?
Trying to translate formula for blending mode
Alternatively, if you're using OpenCV 3.0 you try using seamlessClone.
I got a trick to do it simply copy the area to a new mat, then draw a circle and blur it on the new mat, and use addWeighted to blend it to the image with whatever alpha I need.
Mat roi = myImage.submat(y-20, y+20, x-20, x+20);
Mat mix = roiB.clone();
Imgproc.circle(mix, new Point(20, 20), 12, color, -1);
Core.addWeighted(mix, alpha, roiB, beta, 0.0, mix);
Imgproc.GaussianBlur(mix, mix, new Size(21, 21), 0);
mix.copyTo(roiB);

How to encode emission or specular info in the alpha of a open gl texture

I have an OpenGL texture with UV map on it. I've read about using the alpha channel to store some other value which saves needing to load an extra map from somewhere. For example, you could store specular info (shininess), or an emission map in the alpha since you only need a float for that and the alpha isn't being used.
So I tried it. Writing the shader isn't the problem. I have all that part worked out. The problem is just getting all 4 channels in to the texture like I want.
I have all the maps so in PSD I put the base map in the rgb and the emissions map in the a. But when you save as png the alpha either doesn't save (if you add it as a new channel) or it trashes the rgb by premultiplying the transparency to the rgb (if you apply the map as a mask).
Apparently PNG files support transparency but not alpha channels per se. So there doesn't appear to be a way to control all 4 channels.
But I have read about doing this. So what format can I save it in from PSD that I can load with my image loader in the iPhone?
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:type];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
Does this method accept other file formats? Like TIFF which would allow me to control all 4 channels?
I could use texturetool to make a PVR.. but from the docs it appears to also take a PNG as input.
EDIT:
First to be clear this is in the iPhone.
It might be psd's fault. Like I said, there are two ways to set up the document in my version of psd (cc 14.2 mac) that I can find. One is to manually add a new channel and paste the maps in there. It shows up as a red overlay. The second is to add a mask, option click it and paste the alpha in there. In that case it shows it with the alpa as a transparency with the checkerboard in the alpha zero areas. When I save as png the alpha option greys out.
And when I load the png back in to psd it appears to be premultiplied. I can't get back to my full rgb data in photoshop.
Is there a different tool I can use to merge the two maps into a png that will store it png-32?
TIFF won't work cause it doesn't store alpha either. Maybe I was thinking of TGA.
I also noticed this in my loader...
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef thisContext = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
if (flipImage)
{
CGContextTranslateCTM (thisContext, 0, height);
CGContextScaleCTM (thisContext, 1.0, -1.0);
}
CGColorSpaceRelease( colorSpace );
CGContextClearRect( thisContext, CGRectMake( 0, 0, width, height ) );
CGContextDrawImage( thisContext, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
glBindTexture(GL_TEXTURE_2D, textureInfo[texIndex].texture);
When I create that context the option is kCGImageAlphaPremultipliedLast.
Maybe I do need to try the glkit loader, but it appears that my png is premultiplied.
It is possible to create a PNG with an alpha channel, but you will not be able to read that PNG image using the builtin iOS APIs without a premultiplication. The core issue is that CoreGraphics only supports premultiplied alpha for performance reasons. You also have to be careful to disable Xcode's optimization of PNGs attached to the project file because it does the premultiplication at compile time. What you could do is compile and link in your own copy of libpng after turning off the Xcode PNG processing, and then read the file directly with libpng at the C level. But, honestly this is kind of a waste of time. Just save one image with the RGB values and another as grayscale with the alpha values as 0-255 grayscale values. You can have those grayscale values mean anything you want and you will not have to worry about premult messing things up. Your opengl code will just need to read from multiple textures, not a big deal.

Alpha blending and UIView background color

When I draw semitransparent textures with OpenGL, it looks like that I get them blended with EAGLView backgroundColor.
((EAGLView*)my_view).backgroundColor = [UIColor redColor];
opaque property is set to YES.
Now that image looks red, when I change to black it turns to gray(blended with black), to white it becomes white (even semitransparent black).
What can it be?
my blending function setting is: src BFP_SRC_ALPHA, dest ONE_MINUS_SRC_ALPHA
I tried also(possibly something like premultiplied alpha):
src ONE dest GL_ONE_MINUS_SRC_ALPHA - it gives good result, but I get problems when drawing semitransparent quad(not texture).
the problem is in premultiplied alpha use src ONE dest GL_ONE_MINUS_SRC_ALPHA, and args must be with premultiplied alpha too glColor4f(r*a, g*a, b*a, a)

opencv: Mat2.copyTo(Mat1(Rect)) is giving grayscale only for copied area

I am trying to overlay image over video frame in android(native part, .cpp).I get my video frames in yuv420sp format, i pass this char * (buffer) to opencv and there i create a MAT with it
Mat frame(Size(width,height),8UC1,buff);
The same way,i have loaded my image into a char *(buffer),converted to yuv420SP and in the similar way i create image Mat:
Mat imageMat((Size(width,height),8UC1,imgBuff));
After this i copy the overlay image on the video frame i received as:
Rect roi(X,Y,U,V);
imageMat.copyTo(frame(roi));
and i need this merged frame in same yuv420sp format so after here i return :
return frame.data;//i am returning char * from this api to my .cpp file
The image is overlayed properly but problem is that only the overlayed part is in gray scale,rest full frame is properly coloured!
I just fail to understand whats wrong!
Note:
I tried few things already like:
1. I converted both the things(frame and image) via:
cvtColor(frame,frame,CV_COLOR_yuv420sp2BGR);
but i want response back in yuv420sp format only,and there is no such flag to turn it back to yuv420sp.
2.Tried with 8UC3,didnt really made any difference. Anyway,my video frame is returned coloured,then why the image is in grayscale?
Really stuck here! Any suggestion will be really helpful!

OpenCV and reading image with floating point data

I use OpenCV to read the image. Then I use Matlab to load the same image.
Then I display the images. For OpenCV loaded image, the image is has no picture inside and just gray plane. For Matlab loaded image, it has the image what I want.
The image pixel values are very small floating point data like 0.0021. The code I used to load the image is shown as follow.
`Mat image(IMAGE_ROW, IMAGE_COL, CV_64FC3);
Mat gray(IMAGE_ROW, IMAGE_COL, CV_64FC1);
image = imread(filespath, CV_LOAD_IMAGE_COLOR );// Read the file
cv::imshow("Image", image);
cvtColor( image, gray, CV_BGR2GRAY, 1);
cv::imshow("gray", gray);`
Why I can't have the same image as loaded by Matlab?
well you can't do it with imwrite()/imread() as stated before.
but you can save/load floating point Mats using the FileStorage, like this:
Mat fm = Mat::ones(3,3,CV_32FC3); // dummy data
FileStorage fs("my.yml", FileStorage::WRITE );
fs << "mat1" << fm; //choose any key here, just be consistant with the one below
and read back in:
Mat fm;
FileStorage fs("my.yml", FileStorage::READ );
fs["mat1"] >> fm;
You don't need to explicitly initialize a cv::Mat image before calling cv::imread, it will initialize the image properly according to the size and format of the image read. So it doesn't matter that you've initialized your image with (IMAGE_ROW, IMAGE_COL, CV_64FC3).
OpenCV has no capabilities for writing/reading floating point images. From cv::imwrite manual:
Only 8-bit (or 16-bit in the case of PNG, JPEG 2000 and TIFF)
single-channel or 3-channel (with ‘BGR’ channel order) images can be
saved using this function.
You can load float images with opencv Mat img= imread(filename, CV_LOAD_IMAGE_ANYDEPTH);
Tried #berak solution, but got a "Missing , between elements" exception. As stated in this bug report, you must release the FileStorage object after writing operation, otherwise it will not properly finalise the file writing and thus raising that exception. Then, the corrected version of the codelet should be:
Mat fm = Mat::ones(3,3,CV_32FC3); // dummy data
FileStorage fs("my.yml", FileStorage::WRITE );
fs << "mat1" << fm; //choose any key here, just be consistant with the one below
fs.release(); //Release the file and finish the writing.

Resources