I'm new to python and currently playing around with creating masks for a Word Cloud using pillow and numpy.
I've encountered an issue between an original image and a cropped version of it (cropping done in MS Paint, where I also inverted the colours). When I run the following code:
mask = Image.open("C:/Users/d-j-h/downloads/original.png")
mask = np.array(mask)
mask2 = Image.open("C:/Users/d-j-h/downloads/cropped.png")
mask2 = np.array(mask2)
The original mask displays as expected (type uint8, size (137,361), and if i look at the array you can make out the original image), whereas the cropped image has an additional dimension (type uint8, size (70,294,3), looks nothing like the image and, when I attempt to do some transformations (transform instances of 0 in the image to 255) with the following code
def transform_format(val):
if val == 0:
return 255
else:
return val
transformed_mask = np.ndarray((mask.shape[0],mask.shape[1]), np.int32)
for i in range(len(mask)):
transformed_mask[i] = list(map(transform_format, mask[i]))
it works perfectly for mask (the original image) but not for mask2, even if I change the code (mask>mask2) and add an extra dimension to the np.ndarray. I get the following error message:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Any help is greatly appreciated.
Usually, some images can be read in grayscale by default. but, the cropped image is read as RGB (3 channels) as it appears.
Why it doesn't appear similar to the original? it depends.
Maybe , you should upload the images to answer that.
As a soluation you can crop after reading the original image and converting to numpy , to get what you need:
mask = Image.open("C:/Users/d-j-h/downloads/original.png")
mask = np.array(mask)
mask2 = mask[new_rows_start:rows_end, new_cols_start:cols_end]
This will result in grayscale image, you need to know the new dimensions though
Related
I want to change the pixel value of a grayscale image using OpenCV.
Assume that I have a grayscale image and I want to convert all its pixel to 0 value one at a time. So that the resultant image is completely black. I tried this but there is no change in the image:
image = cv2.imread('test_image.png',0)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
image[i, j] = 0
Result:
display the updated image
In most cases, you want to avoid using double for loops to modify pixel values since it is very slow. A better approach is to use Numpy for pixel modification since OpenCV uses Numpy arrays to display images. To achieve your desired result, you can use np.zeros to create a completely black image with the same shape as the original image.
import cv2
import numpy as np
image = cv2.imread("test_image.png", 0)
black = np.zeros(image.shape, np.uint8)
cv2.imshow('image', image)
cv2.imshow('black', black)
cv2.waitKey(0)
For example with a test image. Original (left), result (right)
I would suggest you to always try manipulating the copy of an image so that the image doesn't get affected in the wrong way. Coming to your question, you can do the following:
import cv2
image = cv2.imread('test_image.png',0)
#Creating a copy of the image to confirm right operation is performed on the image.
image_copy = image.copy()
image_copy[:,:] = [0] #Setting all values to 0.
Using OpenCV and Python, I want to display the left hand half of one image concatenated with the right-hand half of another image, both of the same size - 512x512 pixels. I have identified several ways of doing this, but I am confused about the behaviour of one method. In the following code, assume that only one of the methods is used at any one time and the rest are commented out:
import cv2
import numpy as np
image1 = cv2.imread('img1.png',0)
image2 = cv2.imread('img2.png',0)
#Method 1 - works
image3 = np.concatenate([image1[:,0:256], image2[:,256:512]], axis=1)
#Method 2 - works
image3 = image1[:,:]
image3[:,256:512] = image2[:,256:512]
#Method 3 - works if I don't create image3 with np.zeros first.
#Otherwise displays black image - all zeros - but print displays correct values
image3 = np.zeros(shape=(512,512), dtype=int)
image3[:,0:256] = image1[:,0:256]
image3[:,256:512] = image2[:,256:512]
print(image3)
cv2.imshow("IMAGE", image3)
cv2.waitKey(0)
cv2.destroyAllWindows()
In method 3, I at first mistakenly thought that the new numpy array image 3 would need to be created first and so created an array filled with zeros and then seemingly overwrote that array with the correct values. When I print that array it displays the correct values, but when I show it as an image using cv2.imshow it is all black (i.e. all zeros). Why the difference? I understand that slicing creates a view, not a copy, but can someone please explain what is happening in method 3 and why cv2.imshow displays the underlying array but print doesn't.
Your problem is in:
np.zeros(shape=(512,512), dtype=int)
imshow will show images coded as float(32 bit) with a range of 0.-1. or 8bit(1-4 channels) with a range of 0-255. You are using int, which is 32 bit (in most cases) and it is not a floating point. What you should do to fix it, is to use np.uint8.
np.zeros(shape=(512,512), dtype=np.uint8)
I think also it can be displayed using matplotlib if you want to keep the int, but I am not 100% sure about it.
Given an image and a set of points (number of points >= 3), where the set of points would form a polygon which is my region of interest, my aim is to filter everything in this image that is outside this region of interest, while the area inside it is untouched.
For example, given an image of size 712 x 480 px and the points
[[120,160]
[100,130]
[120,100]
[140,130]]
What I have done is
#Create an array of object rect which represents the region of interest
rect = [[120,160], [100,130], [120,100],[140,130]]
mask = np.array([rect], dtype=np.int32)
#Create a new array filled with zeros, size equal to size of the image to be filtered
image2 = np.zeros((480, 712), np.int8)
cv2.fillPoly(image2, [mask],255)
After this step, image2 would be an array that is 0 everywhere except in the area whose position is exactly the same as my region of interest. After this step what I did was:
output = cv2.bitwise_and(image, image2)
image here is my input image. I get this error:
cv2.error: ..\..\..\..\opencv\modules\core\src\arithm.cpp:1021: error: (-209) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function cv::binary_op
I do not really understand what I did wrong here. Also, is there any alternate solution to my problem? I am still very new to opencv and still learning everything as I go. If there is a better way to do/library to use please suggest. Thanks!
I just found 1 solution to my problem. So instead of writing this
output = cv2.bitwise_and(image, image2)
I first turn image2 into a binary mask, and then bitwise_and it with my original image. So the code should be like this
maskimage2 = cv2.inRange(image2, 1, 255)
out = cv2.bitwise_and(image, image, mask=maskimage2)
Doing this will make everything outside region of interest have binary value of 0. Please comment if you see any flaw.
I am trying to replace a segmented part of an image with it's unsegmented part with OpenCV in Python. The pictures will make you understand what I mean.
The following picture is the first one, before segmentation :
This is the picture after segmentation :
This is the third picture, after doing what I'm talking about :
How can I do this ? Thanks in advance for your help !
This is actually pretty easy. All you have to do is take your picture after segmentation, and multiply it by a mask where any pixel in the mask that is 0 becomes 1, and anything else becomes 0.
This will essentially blacken all of the pixels with the exception of the pixels within the mask that are 1. By multiplying each of the pixels in your image by the mask, you would effectively produce what you have shown in the figure, but the background is black. All you would have to do now is figure out which locations in your mask are white and set the corresponding locations in your output image to white. In other words:
import cv2
# Load in your original image
originalImg = cv2.imread('Inu8B.jpg',0)
# Load in your mask
mask = cv2.imread('2XAwj.jpg', 0)
# Get rid of quantization artifacts
mask[mask < 128] = 0
mask[mask > 128] = 1
# Create output image
outputImg = originalImg * (mask == 0)
outputImg[mask == 1] = 255
# Display image
cv2.imshow('Output Image', outputImg)
cv2.waitKey(0)
cv2.destroyAllWindows()
Take note that I downloaded the images from your post and loaded them from my computer. Also, your mask has some quantization artifacts due to JPEG, and so I thresholded at intensity 128 to ensure that your image consists of either 0s or 1s.
This is the output I get:
Hope this helps!
Basically, you have a segmentation mask and an image. All you need to do is copy the pixels in the image corresponding to the pixels in the label mask. Generally, the mask dimensions and the image dimensions are the same (if not, you need to resize your mask to the image dimensions). Also, the segmentation pixels corresponding to a particular mask would have the same integer value (1,2,3 etc and background pixels would have a value of 0). So, find out which pixel co-ordinates have a value corresponding to the mask value and use those co-ordinates to find out the intensity values in the image. If you know the syntax of how to access a pixel co-ordinate, read an image in the programming environment you are using and follow the aforementioned procedure, you should be able to do it.
I need to calculate histogram on only one part of on my image, but this part has circular shape (like disc). I create mask to find that part on image
cv2.rectangle(mask,(0, 0), (width, height), (0,0,0), -1)
cv2.circle(mask,(int(avgkrug[0]),int(avgkrug[1])),radijusp2,(255,255,255),-1)
cv2.circle(mask,(int(avgkrug[0]),int(avgkrug[1])),radijusp1,(0,0,0),-1)
Using code above, I found my "disc-shape" region of interest.
Now I'm trying to calculate histogram :
for ch, col in enumerate(color):
hist_item = cv2.calcHist([img],[ch],mask,[256],[0,255])
...
but got this error
error: (-215) !mask.data || mask.type() == CV_8UC1 in function cv::calcHist
However, if I save mask on dics and read it using cv2.imread() then this error doesn't appear.
I also tried this use this line
hist_item = cv2.calcHist([slika],[ch],mask.astype(np.uint8),[256],[0,255])
How can I use mask that I create to calc histogram, so I don't need to w/r from disc?
The mask you create needs to be uint8 type , so when creating the mask make it uint8, and then pass it to compute the histogram.
mask = np.zeros(image.shape[:2], dtype="uint8")
and now compute histogram by passing original image, and the curresponding mask.
hist_item = cv2.calcHist([image],[ch],mask,[256],[0,255])