I am using OpenCV 2.4.6. I am trying to convert a 4channel RGB IplImage to 4channel HSV image. Below is my code. Which is giving error "OpenCV Error: Assertion failed in unknown function". I think cvCvtColor supports 3channel images. Is there any way of converting 4channel RGB to HSV or 4channel RGB to 3channel RGB?
IplImage* mCVImageColor = cvCreateImageHeader(cvSize(640,480), IPL_DEPTH_8U, 4);
/*Doing something*/
IplImage* imgHSV = cvCreateImage(cvGetSize(mCVImageColor), IPL_DEPTH_8U, 4);
cvCvtColor(mCVImageColor, imgHSV, CV_BGR2HSV); //This line throws exception
The common assumption is that the 4th channel is an alpha (A) channel. Thus, the correct conversion code is:
cvCvtColor(mCVImageColor, imgHSV, CV_BGRA2HSV);
Notice the A in BGRA.
Also, I guess from your syntax (mCVImage...) that you are using C++. Then, why not using the C++ API of OpenCV?
If you choose to go C++, the documentation is still outdated, and you can find up-to-date color conversion codes for OpenCV 2.4.6 here.
For your case, the correct color conversion code (C++) is: cv::COLOR_BGRA2HSV. But if you are using C++ API, then you should use cv::Mat objects and call the funciton cv::cvtColor(...) instead of using IplaImage's and cv prefixed functions.
Working with OpenCV 3.1, I had this issue but the answer by sansuiso was not working for me.
Instead, I went with the following command to convert from 4 channel color (RGBA) to 3 channel color (RGB):
cvtColor(inputMat, outputMat, CV_BGRA2BGR);
Afterwards, I verified the channels() for each type, and was able to confirm that the alpha channel had been stripped, and my function worked properly that required three channel images.
I have a idea to remove the channel, to convert it to white. Then you can use opencv to do other operations. This method will use PIL package.
image = Image.open("original.png")
image.convert("RGBA") # Convert this to RGBA if possible
pixel_data = image.load()
if image.mode == "RGBA":
# If the image has an alpha channel, convert it to white
# Otherwise we'll get weird pixels
for y in range(image.size[1]): # For each row ...
for x in range(image.size[0]): # Iterate through each column ...
# Check if it's opaque
if pixel_data[x, y][3] < 255:
# Replace the pixel data with the colour white
pixel_data[x, y] = (255, 255, 255, 255)
image.save("noAlphaChannelImage.png")
Related
I've made a program that creates images using OpenCL and in the OpenCL code I have to access the underlaying data of the opencv-image and modify it directly but I don't know how the data is arranged internally.
I'm currently using CV_8U because the representation is really simple 0 black 255 white and everything in between but I want to add color and I don't know what format to use.
This is how I currently modify the image A[y*width + x] = 255;.
Since your A[y*width + x] = 255; works fine, then the underlaying image data A must be a 1D pixel array of size width * height, each element is a cv_8u (8 bit unsigned int).
The color values of a pixel, in the case of OpenCV, will be arranged B G R in memory. RGB order would be more common but OpenCV likes them BGR.
Your data ought to be CV_8UC3, which is the case if you use imread or VideoCapture. if it isn't that, the following information needs to be interpreted accordingly.
Your array index math needs to expand to account for the data's layout:
[(y*width + x)*3 + channel]
3 because 3 channels. channel is 0..2, x and y as you expect.
As mentioned in other answers, you'd need to convert this single-channel image to a 3-channel image to have color. The 3 channels are Blue, Green, Red (BGR).
OpenCV has a method that does just this, cv2.cvtColor(), this method takes an input image (in this case the single channel image that you have), and a conversion code (see here for more).
So the code would be like the following:
color_image = cv2.cvtColor(source_image, cv2.COLOR_GRAY2BGR)
Then you can modify the color by accessing each of the color channels, e.g.
color_image[y, x, 0] = 255 # this changes the first channel (Blue)
I have to render opencv Mat to using DirectX 11.
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
96,
96
);
D2D1_SIZE_U s = D2D1::SizeU(640, 480);
hr = m_d2DeviceContext->CreateBitmap(s, bitmapProp, &m_streamBitmap);
I have to copy opencv matrix to m_streamBitmap.
pImage is a color image with 3 channels.
m_streamBitmap->CopyFromMemory(NULL, reinterpret_cast<BYTE*>(pImage.data),pImage.cols()*3);
This gives distorted image as result.
Can anyone guide me with this.
Thanks in advance ..
Your CopyFromMemory call is copying a three byte color bitmap into a four byte color bitmap. CopyFromMemory does not do format conversion, meaning the format of the source and destination bitmaps must match exactly. In addition, DXGI does not support a three byte color format, so the source bitmap must be modified to four bytes per pixel, even if the fourth is not used. If you cannot change the format of the source bitmap to match the Direct2D bitmap, then you will need to write a conversion function that will expand the bitmap elements to four bytes.
I need to convert OpenCV different types like CV_8UC4 to CV_16UC3.
I tried convertTo(mat, CV_16UC3), but this is returns an empty image (when I save it to the storage it's empty).
convertTo can't change the number of channels.
You'll need two steps:
cv::cvtColor(src, dst, CV_BGRA2BGR)
dst.convertTo(mat, CV_16U)
for example if your 4th channel is an alpha channel and you just want to drop it.
I want to copy a center part (Rectangle) of my image to a completely white Mat (to the same position).
Code:
Mat src = Image.Mat;
Mat dst = new Mat(src.Height, src.Width, DepthType.Cv8U, 3);
dst.SetTo(new Bgr(255, 255, 255).MCvScalar);
Rectangle roi = new Rectangle((int)(0.1 * src.Width), (int)(0.1 * src.Height), (int)(0.8 * src.Width), (int)(0.8 * src.Height));
Mat srcROI = new Mat(src, roi);
Mat dstROI = new Mat(dst, roi);
srcROI.CopyTo(dstROI);
//I have dstROI filled well. CopyTo method is doing well.
//However I have no changes in my dst file.
However I'm getting only white image as a result - dst. Nothing inside.
What i'm doing wrong?
using EmguCV 3.1
EDIT
I have a dstROI Mat filled well. But there is a problem how to apply changes to original dst Mat now.
Changing CopyTo like this:
srcROI.CopyTo(dst);
causes that dst is filled now with my part of src image but not in the centre like i wanted
EDIT 2
src.Depth = Cv8U
As you suggested I check a value of IsSubmatrix property.
Console.WriteLine(dstROI.IsSubmatrix);
srcROI.CopyTo(dstROI);
Console.WriteLine(dstROI.IsSubmatrix);
gives output:
true
false
What can be wrong then?
Ancient question, I know, but it came up when I searched so an answer here might still be being hit in searches. I had a similar issue and it may be the same problem. If src and dst have different numbers of channels or different depths, then a new Mat is created instead. I see that they both have the same depth, but in my case, I had a single channel going into a 3 channel Mat. If your src is not a 3 channel Mat, then this may be the issue (it might be 1 (gray) or 4 channel (BGRA) for example).
According to the operator precedence rules of C# a type cast has higher priority than multiplication.
Hence (int)0.8 * src.Width is equivalent to 0 * src.Width, and the same applies to the other parameters of the roi rectangle. Therefore the line where you create the roi is basically
Rectangle roi = new Rectangle(0,0,0,0);
Copying a 0-size block does nothing, so you're left with the pristine white image you created earlier.
Solution
Parenthesize your expressions properly.
Rectangle roi = new Rectangle((int)(0.1 * src.Width)
, (int)(0.1 * src.Height)
, (int)(0.8 * src.Width)
, (int)(0.8 * src.Height));
I'm trying to reduce the runtime of a routine that converts an RGB image to a YCbCr image. My code looks like this:
cv::Mat input(BGR->m_height, BGR->m_width, CV_8UC3, BGR->m_imageData);
cv::Mat output(BGR->m_height, BGR->m_width, CV_8UC3);
cv::cvtColor(input, output, CV_BGR2YCrCb);
cv::Mat outputArr[3];
outputArr[0] = cv::Mat(BGR->m_height, BGR->m_width, CV_8UC1, Y->m_imageData);
outputArr[1] = cv::Mat(BGR->m_height, BGR->m_width, CV_8UC1, Cr->m_imageData);
outputArr[2] = cv::Mat(BGR->m_height, BGR->m_width, CV_8UC1, Cb->m_imageData);
split(output,outputArr);
But, this code is slow because there is a redundant split operation which copies the interleaved RGB image into the separate channel images. Is there a way to make the cvtColor function create an output that is already split into channel images? I tried to use constructors of the _OutputArray class that accepts a vector or array of matrices as an input, but it didn't work.
Are you sure that copying the image data is the limiting step?
How are you producing the Y ? Cr / Cb cv::mats?
Can you just rewrite this function to write the results into the three separate images?
There is no calling option for cv::cvtColor, that gives it result as three seperate cv::Mats (one per channel).
dst – output image of the same size and depth as src.
source: http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor
You have to copy the pixels from the result (as you are already doing) or write such a conversion function yourself.
Use split. This splits the image into 3 different channels or arrays.
Now converting them back to UIImage is where I am having trouble. I get three grayscale images, one in each array. I am convinced they are the proper channels in cvMat format but when I convert them to UIImage they are grayscale but different grayscale values in each image. If you can use imread and imshow then it should display the images for you after the split. My problem is trying to use the ios.h methods and I believe it reassembles the arrays, instead of transferring the single array. Here is my code using a segmented control to choose which layer, or array, you want to display. Like I said, I get 3 grayscale images but with completely different values. I need to keep the one layer and abandon the rest. Still working on that part of it.
UIImageToMat(_img, cvImage);
cv::cvtColor(cvImage, RYB, CV_RGB2BGRA);
split(RYB, layers);
if (_segmentedRGBControl.selectedSegmentIndex == 0) {
// cv::cvtColor(layers[0], RYB, CV_8UC1);
RYB = layers[0];
_imageProcessView.image = MatToUIImage(RYB);
}
if (_segmentedRGBControl.selectedSegmentIndex == 1) {
RYB = (layers[1]);
_imageProcessView.image = MatToUIImage(RYB);
}
if (_segmentedRGBControl.selectedSegmentIndex == 2) {
RYB = (layers[2]);
_imageProcessView.image = MatToUIImage(RYB);
}
}