I'm struggling to find the (x,y) coordinate of certain RGB values in an image. Lets say I edit an image and put a single pixel of (0,255,5), how can I find the 2D coordinate?
My current approach is using numpy.where, but it doesn't seem to work. I'm aware of opencv storing images in BGR. I don't really want to use the HSV approach and inRange because I just want single pixels of very specific values, so that would be overkill.
import numpy as np
import cv2
im = cv2.imread(image)
point = np.where(im == 5,255,0))
Related
I am trying to build a machine learning algorithm where I need to convert pictures to their binaries. I am using Pillow library to get the data from images. Since the performance of the algorithm is not great, I need extra parameters to thoroughly train the network and one of the extra parameters might be hue.
So is there a method in Python that gives me hue value of an image?
I am not sure what you are really trying to do, as Christoph says in the comments, but you can find the mean hue of all the pixels in an image with PIL like this:
from PIL import Image, ImageStat
# Load image, convert to HSV and split the channels, retain H, discard S and V
H, _, _ = Image.open('image.png').convert('RGB').convert('HSV').split()
# Print the mean Hue across all pixels
print(ImageStat.Stat(H).mean)
Note that I converted to RGB first to avoid problems that may arise if you try this with palette images, CMYK images, images with transparency and greyscale images. See here.
I am dealing with CT images that contain the head of the patient but also 'shadows' of the metalic cylinder.
These 'shadows' can appear down, left or right. In the image above it appears only on the lower side of the image. In the image below it appears in the left and the right directions. I don't have any prior knowledge of whether there is a shadow of the cylinder in the image. I must somehow detect it and remove it. Then I can proceed to segment out the skull/head.
To create a reproducible example I would like to provide the numpy array (128x128) representing the image but I don't know how to upload it to stackoverflow.
How can I achieve my objective?
I tried segmentation with ndimage and scikit-image but it does not work. I am getting too many segments.
12 Original Images
The 12 Images Binarized
The 12 Images Stripped (with dilation, erosion = 0.1, 0.1)
The images marked with red color can not help create a rectangular mask that will envelop the skull, which is my ultimate objective.
Please note that I will not be able to inspect the images one by one during the application of the algorithm.
You could use a combination of erosion (with an appropriate number of iterations) to remove the thin details, followed by dilation (also with an appropriate number of iterations) to restore the non-thin details to approximately the original size.
In code, this would look like:
import io
import requests
import numpy as np
import scipy as sp
import matplotlib as mpl
import PIL as pil
import scipy.ndimage
import matplotlib.pyplot as plt
# : load the data
url = 'https://i.stack.imgur.com/G4cQO.png'
response = requests.get(url)
img = pil.Image.open(io.BytesIO(response.content)).convert('L')
arr = np.array(img)
mask_arr = arr.astype(bool)
# : strip thin objects
struct = None
n_erosion = 6
n_dilation = 7
strip_arr = sp.ndimage.binary_dilation(
sp.ndimage.binary_erosion(mask_arr, struct, n_erosion),
struct, n_dilation)
plt.imshow(mask_arr, cmap='gray')
plt.imshow(strip_arr, cmap='gray')
plt.imshow(mask_arr ^ strip_arr, cmap='gray')
Starting from this image (mask_arr):
One would get to this image (strip_arr):
The difference being (mask_arr ^ strip_arr):
EDIT
(addressing the issues raised in the comments)
Using a different input image, for example a binarization of the input with a much lower threshold will help having larger and non-thin details of the head that will not disappear during erosion.
Alternatively, you may get more robust results by fitting an ellipse to the head.
Rather than "pure" image processing, like Ander Biguri above, I'd suggest maybe a different approach (actually two).
The concept here is to not rely on purely algorithmic image processing, but leverage the knowledge of the specifics of the situation you have:
1) Given the container is metal (as you stated) another approach that might be a lot easier is just thresholding, based on the specific HU number for the metal frame.
While you show the images as simple greyscale, in reality CT images are 16-bit images that are window levelled when viewed in a 256bit greyscale representation - so the pictures above are not a true representation of the full information available in the image data, which is actually 16 bit.
The metal frame would likely have a HU value that is significantly different to (higher than) anything within the anatomy. If that is the case, then a simple thresholding then subtraction would be a much simpler way to remove it.
2) Another approach would also be based on considering the geometry and properties of the specific situation you have:
In the images above, you could look at a vertical profile upwards in the middle of your image (column-wise) to find the location of the frame - with the location being the point that vertical profile crosses into a HU value that matches the frame.
From that point, you could use a flood fill approach (eg scikit flood_fill) to find all connected points within a certain tolerance.
That also would give you a set of points (mask) matching the frame that you could use to remove it from the original image.
I'm thinking that either of these approaches would be both faster and more robust for the situation you're proposing.
There are multiple grayscale images in a folder that I am trying to equalize the brightness. The enhancement has to be applied in all the images except the first which will be our reference image. Also, the change only happens in the brightness of the images and not contrast since I want to preserve all the other details. This means that there is only a simple shift of histogram and no widening. I was trying to use the PIL module to calculate the average brightness. This method is probably faster since I can do it without a numpy array conversion.
The code:
with open("Img_Locations.txt") as file: # Assume the file locations in a text file
img_files = file.read().splitlines()
file.close()
self.images = [[] for x in range(len(img_files))]
for i in range(len(img_files)):
images[i] = Image.open(img_files[i])
im = images[i].convert('L')
stat = ImageStat.Stat(im)
ref_pil_original = int(stat.mean[0])
enhancer = ImageEnhance.Brightness(im)
enhanced_im = enhancer.enhance(1.5)
stat2 = ImageStat.Stat(enhanced_im)
ref_pil_bright = int(stat2.mean[0])
print(ref_pil_original, ref_pil_bright)
The sample output here was:
114 170
129 192
122 183
So the question is why does brightness enhancement when applied to the same factor of 1.5 yield me different differences for each image (basically how does the factor affect the pixels of my image)? If this is the case, what is the fastest way that I can adjust the brightness of my images by a constant factor to make sure that the final averages have the same mean value?
python -- measuring pixel brightness Here the PIL image is read by pixel. So does this mean that I will have to scan the image pixel by pixel to complete my requirement? I would like to know if this is indeed the way to do this since there are already existing functions. Unfortunately, I am aware of only PIL and OpenCV for image analysis and therefore the format of my read images are confined to them both.
I have an image dataset and before feeds it to deep learning algorithm I need to crop it to the same size. All images have different size of black margins as the below image demonstrates.
Any suggestions for a way to crop images with different margin size.
Since your border color is black (nearly perfect black) and will be the same in all the images, I would suggest applying binary threshold making everything white (255) except the black region. Now some of the image regions may get affected too but that's not a problem.
Now find contours in the image and second largest contour will be your region. Calculate rectangular bounding box for this contour and crop the same region in the original image.
First, do a thresholding with a low-intensity threshold value (if your background is definitely completely black, you could even threshold at an intensity of 1) to determine all non-border components.
Next, use Connected-component labeling to determine all isolated foreground components. The central scan-image you are interested in should then always result in the biggest component. Crop out this biggest component to remove the border together with all possible non-black artifacts (labels, letters etc.). You should be left with only the borderless scan.
You can find all the algorithms needed in any basic image processing library. I'd personally recommend looking into OpenCV, they also include phyton bindings.
One way to this could be as follows:
Flood-fill the image with red starting at the top-left corner, and allowing around 5% divergence from the black pixel there.
Now make everything that is not red into white - because the next step after this looks for white pixels.
Now use findContours() (which looks for white objects) and choose the largest white contour as your image and crop to that.
You could consider making things more robust by considering some of the following ideas:
You could normalise a copy of the image to the full range of black to white first in case you get any with near-black borders.
You could check that more than one, or all corner pixels are actually black in case you get images without a border.
You could also flag up issues if your cropped image appears to be less than, say 70%, of the total image area.
You could consider a morphological opening with 9x9 square structuring element as the penultimate step to tidy things up before findContrours().
here is the solution code for this question:
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
import cv2
import numpy as np
import os
path = "data/benign/"
img_resized_dir = "data/pre-processed/benign/"
dirs = os.listdir(path)
def thyroid_scale():
for item in dirs:
if os.path.isfile(path+item):
img = cv2.imread(path+item)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,0,255,0)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
crop_img = img[y+35:y+h-5,x+25:x+w-10]
resize_img = cv2.resize(crop_img, (300, 250), interpolation = cv2.INTER_CUBIC)
cv2.imwrite(img_resized_dir+item, resize_img)
thyroid_scale()
I am fairly new to coding, but I have been doing a lot of research. I have been trying to make my own haar cascade using python and open cv. I have all of my negative samples and a few pictures for my positive ones. I was hoping to run a create_samples command with cv2 but can't find anything for how to do it on windows (only linux, which I tried but my digital oceans server wasn't working). If you have any experience or know of any resources please send them my way.
Basically what I need to do is impose my positive images onto my negatives ones with a tilt angle to create a lot of samples.
You Don't Need OpenCV for image Creation. This is how you can create an image from a 2D array.
import numpy as np
from PIL import Image
#gradient between 0 and 1 for 256*256 1d arrray
array = np.linspace(0,1,256*256)
#reshape to 2d
mat = np.reshape(array,(256,256))
#creates PIL image
img = Image.fromarray(np.uint8(mat*255) , 'L')
img.show()
this code will give you your deserved custom image.
Thank You