Copy part of image to another image with EmguCV - opencv

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));

Related

Image Diffrence Using openCv

Im trying to detect the difference between two images :
image 1 :
image 2 :
The result I want is to have an image that doesn't contain the shared elements.
The problem that I'm facing is that when i do an image.diff, I get some lines around the edges of the shared elements.
and i don't want those to be detected.
Image 3 : is what I'm getting now those lines that have x in red shouldn't be there.
Is there anyway to do this ?
The issue I had is that I generated the second image from the first image using the Erode method and that ate away some pixles,
So instead I used MorphologyEx method.
Mat layersToRemove = new Mat();
Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));
Cv2.MorphologyEx(whiteMask, layersToRemove, MorphTypes.Open, element);
The I applied a simple Substract
Mat output = new Mat();
Cv2.Subtract(image1, layersToRemove, output);
res.SaveImage("C:/output.png");

What format should I use for a Opencv image if I need to access the underlaying data?

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)

Using openCV Blur with BORDER_CONSTANT option?

I am trying to creating a blurring function that can take all possible padding options. However for BORDER_CONSTANT you also need to provide the color, i.e. the numbers that you want to pad your image with. In opencv's documentation of blur I don't see an overload of function blur that takes padding and the color value. Does anyone know how to overcome this?
One thing I thought about doing was padding the image first and the blurring some region of interest with no padding at all, although I can't find a way to do that.
The question referred to was asked by me, so basically I would know if this was a duplicated. This question was relating to cv::blur which also handles padding, however does not have an option of adding the border values for BORDER_CONSTANT. I was asking if anyone knows a workaround.
If you follow the source code for blur, you'll find out that, when the borderType is BORDER_CONSTANT, the value for the border will be Scalar(0,0,0,0).
Just a quick reverse-engineering... If you create a white (255) CV_8UC1 matrix and blurwith a 3x3 filter with BORDER_CONSTANT, you'll see that the result is:
In the angles you'll get: (255*4 + 0*5) / 9 = 113, on the border you get (255*6 + 0*3) / 9 = 170. This demonstrate the the padding is of zeros.
Sample code:
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
Mat1b img(5,5,uchar(255));
blur(img, img, Size(3, 3), Point(-1, -1), BORDER_CONSTANT);
return 0;
}
Basically what I assumed in the original post is correct. If anyone cares for a solution here goes:
copyMakeBorder(image_in_mat, image_in_mat, r, r, r, r, BORDER_CONSTANT, Scalar(myNumbers));
ROI = Rect(r, r, w, h);
image_in_ROI = image_in_mat(ROI);
blur(image_in_ROI, image_out_mat, Size(blockSize, blockSize), Point(-1, -1));
where r is the radius you want to pad with; w,h are width and height of original image; myNumbers - the color you want your padding to have; image_in_mat - input image.

How to show 2 channel Image or chnage it into 3 or one channel in OpenCv

I am new to Open Cv, I want to transform the two images,
here are my images,Left image and right image.
here is my Code
cv::Mat transformMat = cv::estimateRigidTransform(leftImageMat, rightImageMat, true);
transform(leftImageMat, reconMat, transformMat);
but the problem is that reconMat is of 2 channel. so how can I show it in openCv or convert to 1 channel image as shown above right and left images.
You have a fundamental misunderstanding of what cv::transform() does. The documentation
states:
Performs the matrix transformation of every array element.
This means that the numerical value of each element is transformed by the specified matrix.
It looks like you want a geometric transformation. This can be achieved using cv::warpAffine():
cv::Mat transformMat = cv::estimateRigidTransform(leftImageMat, rightImageMat, true);
cv::Mat output;
cv::Size dsize = leftImageMat.size(); //This specifies the output image size--change as needed
cv::warpAffine(leftImageMat, output, transformMat, dsize);

OPENCV: can IplImage* hold double value???

I have to create an image to hold double value (that is -0.0001 or 0.005).
I've used
IplImage* temp = cvCreateImage(size, IPL_DEPTH_32F, 1)
but it doesn't work well. Have you some good ideas?
It works as it should, though you cannot visualize 32F image, you have to convert it to the 8U. See this page. BTW, the const is called CV_32F now.

Resources