OpenCV Encoding to H264 changing original RGB pixel values for gray images - opencv

I have the following issue:
I'm creating a uniform gray color video (for testing) using OpenCV VideoWriter. The output video will reproduce a constant image where all the pixels must have the same value x (25, 51, 76,... and so on).
When I generate the video using MJPG Encoder:
vw = cv2.VideoWriter('./videos/input/gray1.mp4',
cv2.VideoWriter_fourcc(*'MJPG'),
fps,(resolution[1],resolution[0]))
and read the output using the VideoCapture class, everything just works fine. I got a frame array with all pixel values set to (25,51,76 and so on).
However when I generate the video using HEV1 (H.265) or also H264:
vw = cv2.VideoWriter('./videos/input/gray1.mp4',
cv2.VideoWriter_fourcc(*'HEV1'),
fps,(resolution[1],resolution[0]))
I run into the following issue. The frame I got in BGR format follows the next configuration:
The blue channel value is the expected value (x) minus 4 (25-4=21, 51-4=47, 76-4=72, and so on).
The green channel is the expected value (x) minus 1 (25-1=24, 51-1=50, 76-1=75).
The red channel is the expected value (x) minus 3 (25-3=22, 51-3=48, 76-3=73).
Notice that the value is reduced with a constant value of 4,1,3, independently of the pixel value (so there is a constant effect).
What I could explain is a pixel value dependable feature, instead of a fixed one.
What is worse is that if I choose to generate a video with frames consisting in every color (pixel values [255 0 0],[0 255 0] and [0 0 255]) I get the corresponding outputs values ([251 0 0],[0 254 0] and [0 0 252])
I though that this relation was related to the grayscale Y value, where:
Y = 76/256 * RED + 150/256 * GREEN + 29/256 * BLUE
But this coefficients are not related with the output obtained. Maybe the problem is the reading with VideoCapture?
EDIT:
In case that I want to have the same output value for the pixels (Ej: [10,10,10] experimentally I have to create a img where the red and blue channel has the green channel value plus 2:
value = 10
img = np.zeros((resolution[0],resolution[1],3),dtype=np.uint8)+value
img[:,:,2]=img[:,:,2]+2
img[:,:,1]=img[:,:,1]+0
img[:,:,0]=img[:,:,0]+2
Anyone has experience this issue? It is related to the encoding process or just that OpenCV treats the image differently, prior encoding, depending on the fourcc parameter value?

Related

How to connect image regions

I've matrix with values, I've colored the matrix for visual analysis. The green region shows values e.g. 5 and brown shows values 6 and black shows value 0. I want to connect the broken region with value 5. I've tried different structuringElement.g. [110;110;000] and used 2 dilation followed by median filter to get this result.
se_mask = centered(Bool[1 1 0; 1 1 0; 0 0 0])
result = dilate(dilate(gt_mat, se_mask), se_mask)
d_gt_mat = mapwindow(median, result, (5, 5))
I'm not sure whats a better way to connect the broken regions to fill up.
I'm working with JULIA.
The functions in ImageMorphology package might be what you are looking for.
For example, with the first image in the OP, something like this can be done:
using Images
using ImageMorphology
using ImageInTerminal
using IterTools
img = load("/path/to/dir/so-image.png")
gray_img = Gray.(img)
size(gray_img) # (117, 238)
# applying dilate 7 times and then erode 7 times
closed_img =
nth(iterated(erode,nth(iterated(dilate, gray_img),7)),7)
save("/tmp/gray_img.png", gray_img)
save("/tmp/closed_img.png", closed_img)
and the results are:
Original in gray version
After processing

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)

opencv: negative result of matchTemplate with CCOEFF_NORMED

I get several app icons and resize to 36*36. I hope to get similarity between any two of them. I have made them black and white with opencv function threshold. I follow instruction from other questions. I apply matchTemplate with method TM_CCOEFF_NORMED on two icons but get a negative result, which makes me confused.
Based on doc there should not be any negative number in result array. Could anyone explain to me that why I get a negative number and does this negative make sense?
I failed one hour for trying edit my post with code indent error, even if I remove all code part from my edit. That's crazy. I have tried both grayscale and black&white of icon. When two icons are quite different, I will always get negative result.
If I use original icon with size 48*48, thing goes well. I don't know whether it is related with my resize step.
#read in pics
im1 = cv2.imread('./app_icon/pacrdt1.png')
im1g = cv2.resize(cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY), (36, 36), cv2.INTER_CUBIC)
im2 = cv2.imread('./app_icon/pacrdt2.png')
im2g = cv2.resize(cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY), (36, 36), cv2.INTER_CUBIC)
im3 = cv2.imread('./app_icon/mny.png')
im3g = cv2.resize(cv2.cvtColor(im3, cv2.COLOR_BGR2GRAY), (36, 36), cv2.INTER_CUBIC)
#black&white convert
(thresh1, bw1) = cv2.threshold(im1g, 128 , 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
(thresh3, bw3) = cv2.threshold(im3g, 128 , 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
(thresh2, bw2) = cv2.threshold(im2g, 128 , 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
#match template
templ_match = cv2.matchTemplate(im1g, im3g, cv2.TM_CCOEFF_NORMED)[0][0]
templ_diff = 1 - templ_match
sample:
edit2: I define icons with different background color or font color as quite similar ones(but viewer will know they are quite same like image 1 and 2 in my sample). That the reason why I input icon picture as black&white. Hope this make sense.
This problem occurs because both the images are of the same size.
I tried out the same approach but using different image sizes. I used to following images:
Image 1: (125 x 108 pixels) Image
Image 2: (48 x 48 pixels) Template
When I ran the given code for these images it returned an array containing values where each value corresponds to how much the region (of Image) around a certain pixel matches with the template (Template).
Now when you execute cv2.minMaxLoc(templ_match) it returns 4 values:
minimum value: pixel the matches the least in the image when compared with template
maximum value: pixel the matches the most in the image when compared with template
minimum_location: position of occurrence of minimum value
maximum_location: position of occurrence of maximum value
This is what I got:
Out[32]: (-0.15977318584918976, 1.0, (40, 12), (37, 32))
^ ^ ^ ^
| | | |
min_val max_val min_loc max_loc
This result is observed when the image and template are of different sizes. In your case you have resized all the images to the same size as a result you are only getting a single value which is the first value of templ_match. Moreover you must avoid doing templ_match = cv2.matchTemplate(im1g, im3g, cv2.TM_CCOEFF_NORMED)[0][0]
But rather perform templ_match = cv2.matchTemplate(im1g, im3g, cv2.TM_CCOEFF_NORMED) and then obtain the maximum and minimum value along with their locations using : cv2.minMaxLoc(templ_match)

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

How to merge two image without losing intensity in opencv

I have two images in opencv: Image A and Image B.
Image A is output frame from camera.
Image B is alpha transparent image obtained by masking one image.
Before masking Image B it is warped with cvWarpPerspective()
I tried cvAddWeighted() - It looses intensity when you give alpha and beta value
I tried aishack - Even here you looses overall intensity of Output Image
I tried silveiraneto.net - Not helpful in my case
Please help me out with something where I don't lose intensity in the output image after blending.
Thanks in advance
When you say, that you lose intensity... you leave the question about, how you lose it?
Do you loose intensity in the sense:
That when you add the images you hit a maximum intensity, and the rest is discarded.
(Example for a 8 bit pixel addition: Pix1 = 200 i, Pix2 = 150 i. "Pix1 + Pix2 = 350" but max value at 255, so Pix1 + Pix2 = 255)
That the former values of image A is compromised by adding it to Image B, which only covers some parts of the image.
(Example for an 8 bit image: Pix1 = 200 i, Pix2 = 150, (Pix1 + Pix2)/2 = 175, but when the value of a pixel of the second image is zero, Pix2 = 0. Then (Pix1 + Pix2)/2 = 100, which is half the value of the original image)
One of these observations should tell you about what you need to do.
I don't quite know, in accordance to the functions you mentioned, which approach they use.
I finally got the answer.It consist of 5 steps....
Step - 1
cvGetPerspectiveTransform(q,pnt,warp_matrix);
//where pnt is four point x and y cordinates and warp_matrix is a 3 x 3 matrix
Step - 2
cvWarpPerspective(dst2, neg_img, warp_matrix,CV_INTER_LINEAR)
//dst2 is overlay image ,neg_img is a blank image
Step - 3
cvSmooth(neg_img,neg_img,CV_MEDIAN); //smoothing the image
Step - 4
cvThreshold(neg_img, cpy_img, 0, 255, CV_THRESH_BINARY_INV);
//cpy_img is a created image from image_n
Step - 5
cvAnd(cpy_img,image_n,cpy_img);// image_n is a input image
cvOr(neg_img,cpy_img,image_n);
Output - image_n (without loosing intensity of input image)

Resources