contrast_img = cv2.addWeighted(img, 2.5, np.zeros(img.shape, img.dtype), 0, 0)
How to change contrast of half of the image,i'm using the above code ,what change I need to in my code to do so
You could slice out the top half of the image and apply the contrast function to just that.
top_half = img[0:int(height/2), :, :];
I'm fairly certain that with python aliasing applying the contrast to "top_half" would change the original "img" as well, but if not you can always just overlay the top_half onto img with this:
img[0:int(height/2), :, :] = top_half;
Note: images in opencv are numpy arrays with shape [height, width, channels] (grayscale images or other single-channel representations might be missing the last dimension). I'm assuming here that you're working with an rgb (bgr in opencv) image.
Related
I have an image to which I apply a bilateral filter, followed by adaptive thresholding to get the image below.
original image (this is a screenshot off the depth image of the object)
thresholded image
I would like to fit lines to the vertical parts/lines and find the center poiint, output like image below:
I cant seem to understand the output of the cv2.adaptiveThreshold(). How are the purple pixels (i.e my edges) represented? and how can a line be fitted? MWE:
import cv2
image = cv2.imread("depth_frame0009.jpg")
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
bilateral_filter = cv2.bilateralFilter(gray_image, 15, 50, 50)
plt.figure()
plt.imshow(bilateral_filter)
plt.title("bilateral filter")
#plt.imsave("2dimage_gaussianFilter.png",blurred)
plt.imsave("depthmap_image_bilateralFilter.png",bilateral_filter)
th3 = cv2.adaptiveThreshold(bilateral_filter,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
plt.figure()
plt.imshow(th3)
========
edit:
Canny edges
contours
They are represented as an image, a matrix of uint8.
The reason it is purple and yellow is because matplotlib is applying a colormap to it.
I generally prefer to use some specific parameters when plotting image processing output images, eg
plt.imshow(th3, cmap='gray', interpolation='nearest')
If you are specifically interested in finding and fitting lines you may want to use a different representation, such as Hough lines. Once you have the lines in the image you can take the best fit lines and find your center point between them.
I want to extract the screen of the mobile device from an image where mobile is not the largest rectangle. The mobile is placed on a table or mobile image is visible inside a laptop screen. So I am not able to use the largest contour detection algorithm.
If you can help please let me know.
Thanks in advance.
Here I am adding a sample picture:
Sample Image
There are different approaches that you can take:
Probably the most promising method will be to train a deep-learning model with your costume data. Take a look at this article.
You can add some other filters before searching for rectangles. For example, if your phone screen is turned off, you can use HSV color filter for black objects. I would be doing something like that:
blur = cv2.blur(img,(5,5))
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
# Play with these values. They are the HSV lower and upper bounds:
lower_black = np.array([0, 5, 50], np.uint8)
upper_black = np.array([179, 50, 255], np.uint8)
mask = cv2.inRange(hsv, lower_black, upper_black)
# mask = cv2.Canny(mask, 60, 120) - optional
img_res = cv2.bitwise_and(img, img, mask=mask)
(np refers to numpy).
Now try to perform contour detection on img_res. Notice that HSV lower and upper bounds values should be fine-tuned to give you the best results.
If the contour detection doesn't work well on the filtered image, try to apply Canny edge detection on mask, as commented in the code.
I came across this Kaggle kernel that has the following function.
def subtract_gaussian_blur(img):
gb_img = cv2.GaussianBlur(img, (0, 0), 5)
return cv2.addWeighted(img, 4, gb_img, -4, 128)
That converts this RGB image.
Into the following image.
I can see the effect is that it somewhat sharpens the image and turns it into a more grayscale image (not actually grayscale since the image is still RGB) but I'm not actually sure I fully understand what is happening in the function even after reading the OpenCV docs on GaussianBlur and addWeighted.
Also, does this particular image transformation have a specific name that I can do further reading into?
The main step I can see is cv2.addWeighted(img, 4, gb_img, -4, 128). The underlying equation for addWeighted is dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma). In the example here, alpha is 4, beta -4, and gamma 128.
My understanding of how that works is it first performs a gaussian blur to make a denoised version of the image. However as well as removing noise, Gaussian Blurring can also "smear" edges, which is important later. It then subtracts the denoised version from the original, and adds 128 to each pixel colour channel.
In regions where the original pixel is identical to the filtered pixel, this will result in a uniform grey region. In areas where the original and filtered pixels differ a lot, you will end up either with a lighter or darker region depending on whether the intensity of the original or filtered pixel is higher. The differences will be most pronounced around edges in the original image, because those will be strongly "smeared" by the gaussian blur.
The result isn't fully greyscale as addWeighted() is applied to each colour channel of the pixels separately. Areas where the RGB values of the pre and post blur images differ in an unbalanced way (ie the difference between the two red channels is much bigger than between the blue or green channels) there will be a degree of colour rather than just grey.
I am trying to do segmentation of leaf images of tomato crops. I want to convert images like following image
to following image with black background
I have reference this code from Github
but it does not do well on this problem, It does something like this
Can anyone suggest me a way to do it ?
The image is separable using the HSV-colorspace. The background has little saturation, so thresholding the saturation removes the gray.
Result:
Code:
import numpy as np
import cv2
# load image
image = cv2.imread('leaf.jpg')
# create hsv
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# set lower and upper color limits
low_val = (0,60,0)
high_val = (179,255,255)
# Threshold the HSV image
mask = cv2.inRange(hsv, low_val,high_val)
# remove noise
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel=np.ones((8,8),dtype=np.uint8))
# apply mask to original image
result = cv2.bitwise_and(image, image,mask=mask)
#show image
cv2.imshow("Result", result)
cv2.imshow("Mask", mask)
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
The problem with your image is the different coloration of the leaf. If you convert the image to grayscale, you will see the problem for the binarization algorithm:
Do you notice the very different brightness of the bottom half and the top half of the leaf? This gives you three mostly uniformly bright areas of the image: The actual background, the top-half leaf and the bottom-half leaf. That's not good for binarization.
However, your problem can be solved by separating your color image into it's respective channels. After separation, you will notice that in the blue channel the leaf looks very uniformly bright:
Which makes sense if we think about the colors we are talking about: Both green and yellow have very small amounts blue in it, if any.
This makes it easy for us to binarize it. For the sake of a clearer image, i first applied smoothing
and then used the iso_data Threshold of ImageJ (you can however use any of the existing automatic thresholding methods available) to create a binary mask:
Because the algorithm has set the leaf to background (black), we have to invert it:
This mask can be further improved by applying binary "fill holes" algorithms:
This mask can be used to crop the original image to extract the leaf:
The quality of the result image could be further improved by eroding the mask a little bit.
For the sake of completeness: You do not have to smooth the image, to get a result. Here is the mask for the unsmoothed image:
To remove the noise, you first apply binary fill holes, then binary closing followed by binary erosion. This will give you:
as a mask.
This will lead to
Lets say I have the following image where there is a folder image with a white label on it.
What I want is to detect the coordinates of end points of the folder and the white paper on it (both rectangles).
Using the coordinates, I want to know the exact place of the paper on the folder.
GIVEN :
The inner white paper rectangle is always going to be of the fixed size, so may be we can use this knowledge somewhere?
I am new to opencv and trying to find some guidance around how should I approach this problem?
Problem Statement : We cannot rely on color based solution since this is just an example and color of both the folder as well as the rectangular paper can change.
There can be other noisy papers too but one thing is given, The overall folder and the big rectangular paper would always be the biggest two rectangles at any given time.
I have tried opencv canny for edge detection and it looks like this image.
Now how can I find the coordinates of outer rectangle and inner rectangle.
For this image, there are three domain colors: (1) the background-yellow (2) the folder-blue (3) the paper-white. Use the color info may help, I analysis it in RGB and HSV like this:
As you can see(the second row, the third cell), the regions can be easily seperated in H(HSV) if you find the folder mask first.
We can choose
My steps:
(1) find the folder region mask in HSV using inRange(hsv, (80, 10, 20), (150, 255, 255))
(2) find contours on the mask and filter them by width and height
Here is the result:
Related:
Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV)
How to define a threshold value to detect only green colour objects in an image :Opencv
You can opt for (Adaptive Threshold)[https://docs.opencv.org/3.4/d7/d4d/tutorial_py_thresholding.html]
Obtain the hue channel of the image.
Perform adaptive threshold with a certain block size. I used size of 15 for half the size of the image.
This is invariant to color as you expected. Now you can go ahead and extract what you need!!
This solution helps to identify the white paper region of the image.
This is the full code for the solution:
import cv2
import numpy as np
image = cv2.imread('stack2.jpg',-1)
paper = cv2.resize(image,(500,500))
ret, thresh_gray = cv2.threshold(cv2.cvtColor(paper, cv2.COLOR_BGR2GRAY),
200, 255, cv2.THRESH_BINARY)
image, contours, hier = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for c in contours:
area = cv2.contourArea(c)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
# convert all coordinates floating point values to int
box = np.int0(box)
# draw a green 'nghien' rectangle
if area>500:
cv2.drawContours(paper, [box], 0, (0, 255, 0),1)
print([box])
cv2.imshow('paper', paper)
cv2.imwrite('paper.jpg',paper)
cv2.waitKey(0)
First using a manual threshold(200) you can detect paper in the image.
ret, thresh_gray = cv2.threshold(cv2.cvtColor(paper, cv2.COLOR_BGR2GRAY), 200, 255, cv2.THRESH_BINARY)
After that you should find contours and get the minAreaRect(). Then you should get coordinates for that rectangle(box) and draw it.
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(paper, [box], 0, (0, 255, 0),1)
In order to avoid small white regions of the image you can use area = cv2.contourArea(c) and check if area>500 and drawContours().
final output:
Console output gives coordinates for the white paper.
console output:
[array([[438, 267],
[199, 256],
[209, 60],
[447, 71]], dtype=int64)]