I provide the following function to flip the image and its corresponding mask. Now I want to display two images and save them. How can I do that? I need to know this method more than others because it is related to my research work.
import torch
import torchvision.transforms as transforms
from torchvision.utils import save_image
import cv2
from matplotlib import pyplot as plt
import numpy as np
import numpy as np
import cv2
## define functions
def t_random(min=0, max=1):
return min + (max - min) * np.random.rand()
def t_randint(min, max):
return np.random.randint(low=min, high=max)
class augCompose(object):
def __init__(self, transforms=None):
self.transforms = transforms
def __call__(self, img, mask):
if self.transforms is not None:
for op, prob in self.transforms:
if t_random() <= prob:
img, mask = op(img, mask)
return img, mask
def RandomFlip(img, mask, FLIP_LEFT_RIGHT=True, FLIP_TOP_BOTTOM=True):
if FLIP_LEFT_RIGHT and t_random() < 0.5:
img = cv2.flip(img, 1)
mask = cv2.flip(mask, 1)
if FLIP_TOP_BOTTOM and t_random() < 0.5:
img = cv2.flip(img, 0)
mask = cv2.flip(mask, 0)
return img, mask
# This function will read the image using its path with opencv
def Load_Image(Path):
img = cv.imread(Path)[:,:,::-1] # opencv read the images in BGR format
# so we use [:,:,::-1] to convert from BGR to RGB
return img
## Load the image
img = Load_Image("..........\\6192.jpg")
msk = Load_Image("...........\\6192.bmp")
## Call the function
RandomFlip = RandomFlip(img, msk)
## how can I display these two flipped images?
you can plot them with just plt as follows:
# make axes: images are arranged over one row
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2)
# you can change the size of the plot is required
fig_size = (12, 10) # example base size
fig.set_figwidth(fig_size[0] * 2) # where 2 is #columns
fig.set_figheight(fig_size[1] * 1) # 1 is #rows
# plot the images on each axis
ax1.imshow(img)
# additionally you can specify a colormap, e.g.
ax2.imshow(msk, cmap='binary')
# you can set the title, axis labels, legends, as usual, e.g.
ax1.set_title('Image')
ax2.set_title('Mask')
# removes borders
fig.tight_layout()
# finally show the images
plt.show()
If you have more than two images you can rearrange them easily, in a grid-like fashion, by setting nrows and ncols.
You can display the images using either OpenCV or Matplotlib.
If you wish to use OpenCV:
## Load the image
img = Load_Image("..........\\6192.jpg")
msk = Load_Image("...........\\6192.bmp")
## Call the function
flp_img, flp_msk = RandomFlip(img, msk)
## Display the image
cv2.imshow('image',flp_img)
cv2.waitKey(0)
## Display the mask
cv2.imshow('mask',flp_msk)
cv2.waitKey(0)
## Saving the images
cv2.imwrite("flp_img", flp_img)
cv2.imwrite("flp_msk", flp_msk)
If you wish to use Matplotlib you can use the plt.imshow function, but we first need to recolor the image from BGR (the format used by OpenCV) to RGB (the format used by Matplotlib). We will use the same code for saving the images:
## Load the image
img = Load_Image("..........\\6192.jpg")
msk = Load_Image("...........\\6192.bmp")
## Call the function
flp_img, flp_msk = RandomFlip(img, msk)
## Display the image
plt.imshow(cv2.cvtColor(flp_img, cv2.COLOR_BGR2RGB))
plt.show()
## Display the mask
plt.imshow(cv2.cvtColor(flp_msk, cv2.COLOR_BGR2RGB))
plt.show()
## Saving the images
cv2.imwrite("flp_img", flp_img)
cv2.imwrite("flp_msk", flp_msk)
Related
I'm trying to crop some binary images. The images have a black background and white silhouette. I want to crop all of my images, removing any excess background. I've tried doing this using the function below, however, the output images tend to also crop the edges of the silhouette, whilst I would like to keep these. I haven't been successful in finding a way to do this. Any ideas on how this could be done?
example images
def crop_image(img,tol):
mask = img > tol
return img[np.ix_(mask.any(1),mask.any(0))]
You can get the coordinates from cv2.findNonZero() function, and cv2.boundingRect()
import matplotlib.pyplot as plt
import numpy as np
import cv2
def downloadImage(URL):
"""Downloads the image on the URL, and convers to cv2 RGB format"""
from io import BytesIO
from PIL import Image as PIL_Image
import requests
response = requests.get(URL)
image = PIL_Image.open(BytesIO(response.content))
return cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB)
URL = "https://i.stack.imgur.com/WgnXW.jpg"
# Read image
img = downloadImage(URL)
# crop blank frame
initialImage = img[11:2330, 11:2208]
fig, ax = plt.subplots(1, 3)
ax[0].imshow(initialImage)
ax[0].set_title('Initial Image')
# crop the empty space
coords = cv2.findNonZero(cv2.cvtColor(initialImage, cv2.COLOR_BGR2GRAY))
x, y, w, h = cv2.boundingRect(coords)
cropedIMag = initialImage[y:y+h, x:x+w]
ax[1].imshow(cropedIMag)
ax[1].set_title('Cropped Image')
# Add an empty frame to the image
extraPixels = 100
paddedImag = np.pad(cropedIMag, ((extraPixels, extraPixels),(extraPixels, extraPixels),(0,0)), 'constant')
ax[2].imshow(paddedImag)
ax[2].set_title('Cropped \nand padded Image')
plt.show()
I am have having two images, namely Fig 1 and Fig 2. Both taken from the same source but not aligned. The task is to find the common data point among these two images and draw lines between the data points that match in both the images., I am looking at this figure should be like Fig 4.
So far, I have used OpenCV and written the following codes:
import cv2
import matplotlib.pyplot as plt
img_file1= "Fig_1.png"
img_file2= "Fig_2.png"
img1= cv2.imread(img_file1)
img2= cv2.imread(img_file2)
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
figure, ax = plt.subplots(1, 2, figsize=(16, 8))
ax[0].imshow(img1, cmap='gray')
ax[1].imshow(img2, cmap='gray')
#sift
sift = cv2.xfeatures2d.SIFT_create()
keypoints_1, descriptors_1 = sift.detectAndCompute(img1,None)
keypoints_2, descriptors_2 = sift.detectAndCompute(img2,None)
#feature matching
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
matches = bf.match(descriptors_1,descriptors_2)
matches = sorted(matches, key = lambda x:x.distance)
img3 = cv2.drawMatches(img1, keypoints_1, img2, keypoints_2, matches[:50], img2, flags=2)
plt.imshow(img3),plt.show()
This gives to be not expected result, see figure 4. Plus look quite messy and unclear.
Can anyone help me with how to do this? Thanks in advance.
Fig 1
Fig 2
img3
Fig 3
The transformation seems purely translational. Try template matching by normalized grayscale correlation.
Basically, this seems to me a registration problem (the images need to be registered).
Here is what you can do:
find the location of the points with connected components analysis
calculate the shift needed to register the two images. Here it seems your images are only translated so a simple crosscorrelation-based registration is enough.
from skimage.registration import phase_cross_correlation
from skimage.io import imread
from skimage.measure import label, regionprops
from skimage.filters import threshold_otsu
from matplotlib.pyplot import imshow, plot, figure
import numpy as np
# Load images
img_a = imread("671OL.jpg", as_gray=True)
img_b = imread("zpevD.jpg", as_gray=True)
# apply threshold
th_img_a = img_a > threshold_otsu(img_a)
th_img_b = img_b > threshold_otsu(img_b)
# measure connected component
img_lable = label(th_img_a)
r_props = regionprops(img_lable)
figure(figsize=(15,7))
rows, cols = img_b.shape
# calculate the registration (shift) of the two images
flow = phase_cross_correlation(th_img_a, th_img_b)
# stack the images and trace the segments that connect the points
d=10
# a vertical white bar between the two pictures
vbar=np.ones((rows,d))
xshift = cols+d
dy,dx = flow[0]
dx=dx + xshift
imshow(np.hstack([img_a, vbar, img_b]), cmap='gray')
for rp in r_props:
y0,x0 = rp.centroid
x1 = x0 + dx
y1 = y0 - dy
if y1<rows and x1 < 2*cols + d:
# filter out points that are not in img_b
plot([x0,x1],[y0,y1], '--', alpha=0.5)
I am trying to find the dominant color in a frame in a video. This works well, however, my frames are somehow converted into different colors. Yellow/pink becomes blue/purple-ish, but black and white stay the same (thus it is not the inverted colors).
Does anyone know where it comes from and how I can change it so that the original colors are kept? This is my code:
import cv2
from sklearn.cluster import KMeans
from collections import Counter
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.patches as patches
video = cv2.VideoCapture('video.mp4')
def show_blurred_image(image, dominant_color):
frame_to_blur = Image.fromarray(image)
blurred_frame = cv2.blur(image, (200,200))
blurred_frame = Image.fromarray(blurred_frame)
plt.subplot(121),plt.imshow(frame_to_blur),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blurred_frame),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
R = round(dominant_color[0])
G = round(dominant_color[1])
B = round(dominant_color[2])
custom_color = '#%02x%02x%02x' % (R, G, B)
print(custom_color)
rect = patches.Rectangle((1620,0),300,1080,linewidth=1,
fill = True,
edgecolor=custom_color,
facecolor=custom_color)
ax = plt.gca()
ax.add_patch(rect)
plt.show()
def get_dominant_color(image, k=4, image_processing_size = None):
"""
takes an image as input
returns the dominant color of the image as a list
dominant color is found by running k means on the
pixels & returning the centroid of the largest cluster
processing time is sped up by working with a smaller image;
this resizing can be done with the image_processing_size param
which takes a tuple of image dims as input
>>> get_dominant_color(my_image, k=4, image_processing_size = (25, 25))
[56.2423442, 34.0834233, 70.1234123]
"""
#resize image if new dims provided
if image_processing_size is not None:
image = cv2.resize(image, image_processing_size,
interpolation = cv2.INTER_AREA)
#reshape the image to be a list of pixels
image = image.reshape((image.shape[0] * image.shape[1], 3))
#cluster and assign labels to the pixels
clt = KMeans(n_clusters = k)
labels = clt.fit_predict(image)
#count labels to find most popular
label_counts = Counter(labels)
#subset out most popular centroid
dominant_color = clt.cluster_centers_[label_counts.most_common(1)[0][0]]
return list(dominant_color)
dominant_colors = []
show_frame = 10
frame_nb = 0
while(video.isOpened()):
ret, frame = video.read()
if ret == True:
if (frame_nb == show_frame):
dominant_color = get_dominant_color(frame)
show_blurred_image(frame, dominant_color)
frame_nb += 1
else:
break
video.release()
cv2.destroyAllWindows()
OpenCV loads images in a BGR format, while PIL and matplotlib works with the RGB format. If you want to use the libraries together, you need to convert the images in the right color spaces.
In your case :
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
OK so newbie here that has been working on a set of homework problems with the original post here: How do I make a mask from one image and then transfer it to another?
. The original idea was to take the DAPI image (grey image) and apply it as a mask to the NPM1 (green) image. After implementing the suggested code from HansHirse (thanks!) along with some other code I had been making for the homework problem I finally got a working histogram of all compatible cells in the image. The "compatibility" bit is that any cells touching the border weren't supposed to be counted. However, I still need to find a way to get histograms of each individual cell as well. I've attached the original images from the post too:
To do this, I tried blob_doh and one other method to get segmented regions of each cell but have no idea as to how I can apply these coordinates to an image for the histogram.
PS. The code is a bit messy. I segmented the code such that the blob_doh is near the bottom and the other method is also its own separate piece at the very bottom. Sorry!
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from skimage.feature import blob_dog, blob_log, blob_doh
from skimage.color import rgb2gray
import cv2
import mahotas as mh
import scipy
from scipy import ndimage
import matplotlib.patches as mpatches
from skimage import data
from skimage.filters import threshold_otsu
from skimage.segmentation import clear_border
from skimage.measure import label, regionprops
from skimage.morphology import closing, square
from skimage.color import label2rgb
# Read image into numpy array
image = cv2.imread("NOTREATDAPI.jpg",0)
dna = np.array(image) # must be gray-scale image
plt.show()
# Remove extraneous artifacts from image; set the threshold
dnaf = ndimage.gaussian_filter(dna, 8) #gaussian filter for general image
T = mh.thresholding.otsu(dnaf) # set threshold via mahotas otsu thresholding
theta=np.array(dnaf > T) #setting mask of values in image to calculated otsu threshold
cleared = clear_border(theta) #removes all cells that are in contact with the image border
epsilon = np.array(cleared) #final masked DAPI product
print("DAPI MASK USING GAUSSIAN FILTER AND OTSU THRESHOLDING");
plt.imshow(epsilon)
plt.show()
# Load and reset original images
image = cv2.imread("NOTREATDAPI.jpg",0) #The DAPI Image
image1 = cv2.imread("NOTREATNPM1.jpg",0) #The NPM1 Image
print("Original DAPI Image");plt.imshow(image);plt.show() #The DAPI Image
print("Original NPM1 Image");plt.imshow(image1);plt.show() #The NPM1 Image
# Create an array of bool of same shape as image
maskAboveThreshold = epsilon > 0 #Use mask array from above - include only values above non-masked zeros
print("Final Masked Image of NPM1"); plt.imshow(image1 *
maskAboveThreshold, cmap='gray')
plt.show()
True_NPM1= image1 * maskAboveThreshold # Final masked version of NPM1 set back to grayscale
# Create a mask using the DAPI image and binary thresholding at 25
_, mask = cv2.threshold(True_NPM1, 1, 255, cv2.THRESH_BINARY)
# Do some morphological opening to get rid of small artifacts
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN,
cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15)))
# Calculate the histogram using the NPM1 image and the obtained binary
mask
hist = cv2.calcHist([image1], [0], mask, [256], [0, 256])
# Show bar plot of calculated histogram
plt.bar(np.arange(256), np.squeeze(hist))
plt.show()
# Show mask image
plt.imshow(mask)
plt.show()
#blob_doh way of segmenting the cells ------
import cv2 as cv
from PIL import Image, ImageDraw
image10 = np.array(Image.open("OXALIDAPI.jpg"))
plt.imshow(image10)
#Convert to gaussian image with thresholds
image10 = cv2.imread("OXALIDAPI.jpg",0)
dna = np.array(image10) # gray-scale image
plt.show()
# Remove extraneous artifacts from image; set the threshold
dnaf = ndimage.gaussian_filter(dna, 8) #gaussian filter for general image
T = mh.thresholding.otsu(dnaf) # set threshold via mahotas otsu thresholding
theta=np.array(dnaf > T) #setting mask of values in image to calculated otsu threshold
cleared = clear_border(theta) #removes all cells that are in contact with the image border
image = np.array(cleared) #final masked DAPI product
#print("DAPI MASK USING GAUSSIAN FILTER AND OTSU THRESHOLDING");
plt.imshow(epsilon)
plt.show()
# Convert image to grayscale
image_gray = rgb2gray(image)
plt.imshow(image_gray,cmap="gray")
def plot_blobs(img,blobs):
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.imshow(img, interpolation='nearest')
for blob in blobs:
y, x, r = blob
c = plt.Circle((x, y), r*1.25, color="red", linewidth=1, fill=False)
ax.add_patch(c)
# blob_doh
blobs_doh = blob_doh(image_gray, min_sigma=10, max_sigma=256,
threshold=.025)
plot_blobs(image,blobs_doh)
#get blob coordinates
def filter_blobs(blobs,r_cutoff=5):
new_blobs = []
for b in blobs:
if b[2] > r_cutoff:
new_blobs.append(b)
return new_blobs
new_blobs = filter_blobs(blobs_doh)
#plot_blobs(image,new_blobs)
print(new_blobs)
#Other method of segmenting cells. maybe useful?
yeta = cv2.imread("NOTREATDAPI.jpg",0)
image = np.array(yeta)
# apply threshold
dnaf = ndimage.gaussian_filter(image, 8)
T = mh.thresholding.otsu(dnaf) # set threshold
plt.imshow(dnaf > T)
epsilon=np.array(dnaf > T)
plt.show()
# remove artifacts connected to image border
cleared = clear_border(epsilon)
# label image regions
label_image = label(cleared)
image_label_overlay = label2rgb(label_image, image=image)
fig, ax = plt.subplots(figsize=(6, 6))
ax.imshow(image_label_overlay)
for region in regionprops(label_image):
# take regions with large enough areas
if region.area >= 50:
# draw rectangle around individual cells
minr, minc, maxr, maxc = region.bbox
rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr,
fill=False, edgecolor='red', linewidth=0.5)
ax.add_patch(rect)
#ax.set_axis_off()
#plt.tight_layout()
plt.show()
howzer=np.array(image_label_overlay)
What you are looking for is cv2.connectedComponents. Basically, once you have the binary mask that separate the cells, you try to label each connected component of the mask as one cell:
# I choose OTSU instead of binary, but they are not much different in this case
_, mask = cv2.threshold(dapi, 25, 255, cv2.THRESH_OTSU)
# compute the connected component
labels, markers = cv2.connectedComponents(mask)
# load 2nd image in grayscale
# as your 2nd image is only green/black
npm1 = cv2.imread('npm1.jpg', cv2.IMREAD_GRAYSCALE)
# for you image (and usually), labels[0] is the background
for label in labels[1:]:
# compute the histogram over the entire 256 levels of intensity
hist, bins = np.histogram(npm1[markers==label], bins=range(256))
# do whatever you like to hist
# note that bins=range(256) and hist only have 255 values
plt.bar(bins[1:], hist)
plt.title('cell number: {:}'.format(label))
So for example the histogram of the first and second cells:
And the cell markers are:
I am new to opencv and trying to convert RGB images to LAB color space. I am doing that using below code.
data_path = 'D:/Images/'
image_name= '1.png'
img = cv2.imread(os.path.join(data_path, image_name),cv2.IMREAD_COLOR) # Reads image from disk
img = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) # changes RGB to LAB color space
img = img [127.5, 1, 127.5] # This i was trying to get a-channel only but gives error
Now I just want to use only a-channel of the LAB Image to feed to my program as 1 channel input. How can I use only a-channel of the LAB color space image?
I am using opencv2 and python to solve this problem
import cv2
input = cv2.imread('path_to_image.png')
cv2.imshow('Hello World', input)
cv2.waitKey(0)
cv2.destroyAllWindows()
lab = cv2.cvtColor(input,cv2.COLOR_BGR2LAB)
cv2.imshow("l*a*b",lab)
L,A,B=cv2.split(lab)
cv2.imshow("L_Channel",L) # For L Channel
cv2.imshow("A_Channel",A) # For A Channel (Here's what You need)
cv2.imshow("B_Channel",B) # For B Channel
cv2.waitKey(0)
cv2.destroyAllWindows()
Hope this helps you to solve your problem
I have resolved my issue with below line of code
l_channel, a_channel, b_channel = cv2.split(img) #splits the image into 3 channles l, a and b
it separates the image into l, a and b channels which I wanted. It was easy but as I am new to opencv I did not know about it.
Here is the way to plot Lab channels in python. You can find more details in this article that I've used as a reference.
from keras.preprocessing.image import img_to_array, load_img
from skimage.color import rgb2lab, lab2rgb
import matplotlib.pyplot as plt
import numpy as np
def extract_single_dim_from_LAB_convert_to_RGB(image,idim):
'''
image is a single lab image of shape (None,None,3)
'''
z = np.zeros(image.shape)
if idim != 0 :
z[:,:,0]=80 ## I need brightness to plot the image along 1st or 2nd axis
z[:,:,idim] = image[:,:,idim]
z = lab2rgb(z)
return(z)
def plot_lab_spectrums():
# Get image
img = img_to_array(load_img("<image_path>",target_size=(400,400)))
lab = rgb2lab(img/255.0)
lab_l = extract_single_dim_from_LAB_convert_to_RGB(lab,0)
lab_a = extract_single_dim_from_LAB_convert_to_RGB(lab,1)
lab_db = extract_single_dim_from_LAB_convert_to_RGB(lab,2)
# Plot the results
fig, axes = plt.subplots(ncols=3, figsize=(12, 4))
data = [('L: lightness', lab_l), ('a: green-magenta channel', lab_a), ('b: blue-yellow channel', lab_db)]
for ax, (title, img) in zip(axes, data):
ax.set_title(title)
ax.imshow(img)
ax.axis('off')
fig.tight_layout()
plt.show()
plot_lab_spectrums()