As shown in this image, I want to label the edges of three branches with purple color and filter other area as purely white color (or other background color). I use Laplacian and sober to do image gradient and then use canny method to do edge detection. However, it does not reach my expectation.
import cv2
import numpy as np
from matplotlib import pyplot as plt
if __name__ == '__main__' :
# Read image
im = cv2.imread("crop.jpg")
# Calculation of Laplacian
laplacian = cv2.Laplacian(imCrop,cv2.CV_64F)
edges = cv2.Canny(laplacian,35,35)
Try to improve it to get your goal:
import cv2
image = cv2.imread("test.jpg")
#convert to hsv
i = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
i[: ,:, 0]=0
i[: ,:, 2]=0
#s channel
cv2.imshow("s channel", i)
I came up with a solution as below,
import cv2
import numpy as np
from matplotlib import pyplot as plt
if __name__ == '__main__' :
# Read image
im = cv2.imread("crop.jpg")
a=np.copy(im)
a[:,:,0]=255
a[:,:,1]=255
a[a>150]=255
plt.imshow(a)
Related
I'm a newbie to tensorflow and keras, and I'm trying to create a CNN model for The Street View House Numbers (SVHN) dataset. The dataset contains color images, and I want to turn them in grayscale. I found some code on the web that claims they're turning image to grayscale, but it just changes colors.
People are reading the second image with a gray colormap. Is there any way to actually turn this image to grayscale?
(I do not know how to process an image in this kind of programming languages. If this is a dumb question, please forgive me and provide a brief explain.)
I provided images and code below, I'll be grateful for any help.
Code:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
#Read picture:
picture = plt.imread('google.jpg')
print("google logo's shape is: ",picture.shape) #(500, 500, 3)
#saving picture as an np array:
pic_array = np.array(picture)
#Turning image to grayscale
grayscale_pic = np.expand_dims(np.dot(pic_array[...,:3],[0.299, 0.587, 0.144]),axis = 0)
#Dimensions shifted, (probly my mistake):
grayscale_pic = np.moveaxis(grayscale_pic, 0, -1)
print("shape of grayscale pic = ", grayscale_pic.shape) # (500, 500, 1)
plt.imshow(picture) #Figure_1
plt.show()
plt.imshow(grayscale_pic) #Figure_2
plt.show()
U can convert a normal image to grayscale using opencv like this:
import cv2
gray = cv2.cvtColor(picture,cv2.COLOR_RGB2GRAY)
If u prefer numpy over opencv, then u can use this:
gray = np.dot(picture[...,:3], [0.2989, 0.5870, 0.1140])
You can use matplotlib with weights:
import numpy as np
import matplotlib.pyplot as plt
an_image = plt.imread('google.png')
rgb_weights = [0.2989, 0.5870, 0.1140]
grayscale_image = np.dot(an_image[..., :3], rgb_weights)
plt.axis('off')
plt.imshow(grayscale_image, cmap=plt.get_cmap("gray"), aspect='auto')
plt.show()
Output:
If you remove aspect='auto' parameter:
or you can use opencv
import cv2
an_image = cv2.imread("google.png")
grey_image = cv2.cvtColor(an_image, cv2.COLOR_BGR2GRAY)
or you can use PIL library
from PIL import Image
img = Image.open('google.png').convert('LA')
LA mode is L (8-bit pixels, black and white) with ALPHA desinged for .gif and .png. If your images are .jpeg use L.
Output:
There can be several ways to do this. One potential way is to utilize PIL(Pillow) library:
from PIL import Image
import matplotlib.pyplot as plt
picture = Image.open('google.jpg')
grayscale_pic = picture.convert('LA')
grayscale_pic.save('grayscale.png')
fig,ax = plt.subplots(nrows=1, ncols=2)
plt.subplot(1,2,1)
plt.imshow(picture)
plt.subplot(1,2,2)
plt.imshow(grayscale_pic)
plt.show()
Output:
I'm using scikit-image for computer vision.
I will use find contours to obtain the contours of the grayscale image input but the list returned contain the contours in the image all in the first location.
The result that I want to obtain is the only out contour of the image, for this reason I try to separate the contours with a for cycles but it requires very long time and the result is not good. Can anyone help me?
The code is reported below:
import numpy as np
from skimage.io import imread
from skimage.measure import moments, moments_hu, find_contours, approximate_polygon
from skimage.feature import canny
from matplotlib import pyplot as plt
#%% Opening image section
reference_image = imread('referenceImage.jpg', as_gray= True)
reference_contours = find_contours(reference_image, 0.8, fully_connected='high')
first = True
added = False
reference_contours_list = []
for contours in reference_contours:
for con in contours:
if first:
first = False
reference_contours_list.append(np.array(np.array([con])))
else:
for index, past_con in enumerate(reference_contours_list):
for past_c in past_con:
if con[0] in range(int(round(past_c[0])) - 1, int(round(past_c[0])) + 2):
reference_contours_list[index] = np.append(reference_contours_list[index], np.array(np.array([con])), axis=0)
Just want to retain the lettuce, I have hundreds of image like this and would be comparing the size of lettuce, so to began with I tried the canny edge detection but it doesn't seems to work, any idea how shall move ahead with this
A possible approach is by using the Graph Segmentation method (cv::ximgproc::segmentation::GraphSegmentation), that you apply to the image converted to HSV or HSL, where you set the V or L plane to a constant to flatten illumination.
You can convert the RGB image into HSV image and segment the Green color region.
import cv2
import numpy as np
frame=cv2.imread('a.png')
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower = np.array([50,50,50])
upper = np.array([70,255,255])
mask = cv2.inRange(hsv, lower, upper)
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
You may get away with thresholding as long as you fix your lighting (method 1 listed below), if not, you might need a simple classifier method (for example a clustering technique, method 2) in conjunction with connected components and assumption on the location of the plant or color to assign the detected class to the plant.
from scipy.misc import imread
import matplotlib.pyplot as plt
import matplotlib.patches as patches
%matplotlib inline
import matplotlib
import numpy as np
# read the image
img = imread('9v5wv.png')
# show the image
fig,ax = plt.subplots(1)
ax.imshow(img)
ax.grid('off')
# show the r,g,b channels separately.
for n,d in enumerate([('r',0),('g',1),('b',2)]):
k,v = d
plt.figure(n)
plt.subplot(131)
plt.imshow(arr[:,:,v],cmap='gray')
plt.grid('off')
plt.title(k)
plt.subplot(133)
_=plt.hist(arr[:,:,v].ravel(),bins=100)
# method 1, rgb thresholding will not work when lighting changes
arr = img
r_filter = lambda x: x[:,:,0] < 100
g_filter = lambda x: x[:,:,1] > 80
b_filter = lambda x: x[:,:,2] < 200
mask=np.logical_and(np.logical_and(r_filter(arr),g_filter(arr)),b_filter(arr))
plt.imshow(mask,cmap='gray')
plt.grid('off')
# method 2, kmeans clustering
from sklearn.cluster import KMeans
arr = matplotlib.colors.rgb_to_hsv(img[:,:,0:3])
# ignore v per Yves Daoust
data = np.array(arr[:,:,0:2])
x,y,z = data.shape
X = np.reshape(data,(x*y,z))
kmeans = KMeans(n_clusters=6, random_state=420).fit(X)
mask = np.reshape(kmeans.labels_,(x,y,))
plt.imshow(mask==0,cmap='gray')
plt.grid('off')
Based on a solution that I read at How to define the markers for Watershed in OpenCV?, I am trying apply watershed to grayscale data (not very visible but not all black), extracted from netcdf (precipitation data).
Here is a black and white version of the data (threshold at 0) so that you can see more easily, and the markers I want to use to define the different basins (basically just another threshold where precipitation is more intense).
The code I'm running is as follows:
import os,sys,string
from netCDF4 import Dataset as nc
import cv2
import numpy as np
import matplotlib.pyplot as mpl
import scipy.ndimage as ndimage
import scipy.spatial as spatial
from skimage import filter
from skimage.morphology import watershed
from scipy import ndimage
filename=["Cmorph-1999_01_03.nc"]
nc_data=nc(filename[0])
data=nc_data.variables["CMORPH"][23,0:250,250:750]
new_data=np.flipud(data)
ma_data=np.ma.masked_where(new_data<=0,new_data)
ma_conv=np.ma.masked_where(new_data<=2,new_data)
## Borders
tmp_data=ma_data.filled(0)
tmp_data[np.where(tmp_data!=0)]=255
bw_data=tmp_data.astype(np.uint8)
border = cv2.dilate(bw_data, None, iterations=5)
border = border - cv2.erode(border, None)
## Markers
tmp_conv=ma_conv.filled(0)
tmp_conv[np.where(tmp_conv!=0)]=255
bw_conv=tmp_conv.astype(np.uint8)
lbl, ncc = ndimage.label(bw_conv)
lbl = lbl * (255/ncc)
lbl[border == 255] = 255
lbl = lbl.astype(np.int32)
## Apply watershed
cv2.watershed(ma_data, lbl)
lbl[lbl == -1] = 0
lbl = lbl.astype(np.uint8)
result = 255 - lbl
I have the following error for the watershed in opencv-2.4.11/modules/imgproc/src/segmentation.cpp:
error: (-210) Only 8-bit, 3-channel input images are supported in function cvWatershed
For what I saw on the internet, this is due to the fact that the grayscale data is a 2D image and watershed needs a 3D image (from RGB). Indeed, I tried the script with a jpg image and I worked perfectly.
This problem is mentionned here but the answer given was finally rejected. And I can't find any more recent link answering the question.
To try to solve this, I created a 3D array from the 2D new_data:
new_data = new_data[..., np.newaxis]
test=np.append(new_data, new_data, axis=2)
test=np.append(new_data, test, axis=2)
But, as expected, it didn't solve the problem (same error message).
I also tried to save the plot from matplotlib to get RGB data:
fig = mpl.figure()
fig.add_subplot(111)
fig.tight_layout(pad=0)
mpl.contourf(ma_data,levels=np.arange(0,255.1,0.1))
fig.canvas.draw()
test_data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
test_data = test_data.reshape(fig.canvas.get_width_height()[::-1] + (3,))
But the size of the test_data created is different from ma_data (+ I can't get rid of the labels).
So, I am stuck here. Ideally, I want to apply the watershed on the 2D grayscale image directly and/or limit the number of operations as much as possible.
As yapws87 mentioned, there was indeed a problem with the format I was presenting to the watershed function.
Doing try_data=ma_data.astype(np.uint8) removed the error message.
Here is a minimal example that works now:
import os,sys
from netCDF4 import Dataset as nc
import cv2
import numpy as np
import scipy.ndimage as ndimage
from skimage.morphology import watershed
from scipy import ndimage
basename="/home/dcop696/Data/CMORPH/precip/CMORPH_V1.0/CRT/8km-30min/1999/"
filename=["Cmorph-1999_01_03.nc"]
fileslm=["/home/dcop696/Data/LSM/Cmorph_slm_8km.nc"]
nc_data=nc(basename+filename[0])
data=nc_data.variables["CMORPH"][23,0:250,250:750]
new_data=np.flipud(data)
ma_data=np.ma.masked_where(new_data<=0,new_data)
try_data=ma_data.astype(np.uint8)
## Building threshold
tmp_data=ma_data.filled(0)
tmp_data[np.where(tmp_data!=0)]=255
bw_data=tmp_data.astype(np.uint8)
## Building markers
ma_conv=np.ma.masked_where(new_data<=2,new_data)
tmp_conv=ma_conv.filled(0)
tmp_conv[np.where(tmp_conv!=0)]=255
bw_conv=tmp_conv.astype(np.uint8)
markers = ndimage.label(bw_conv)[0]
## Watershed
labels = watershed(-try_data, markers, mask=bw_data)
you can try changing your image fram gray to a BGR color space using
cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
before passing your image to watershed algorithm
The input is an image(document) from the scanner and my task is to crop the background and return only the document, just like this: Input Output
I've done this through thresholding and getbbox:
import matplotlib.pyplot as plt
import matplotlib.image as pli
from skimage.filters import threshold_otsu as otsu
from PIL import Image
cnh_gray = Image.open("cnh.jpg").convert('L')
cnh_gray.save('cnhgray.jpg')
img = pli.imread('cnhgray.jpg')
imagem = Image.open('cnhgray.jpg')
thresh = otsu(img)
mask = img < thresh
msk = Image.fromarray(mask,'L')
box = msk.getbbox()
crop = imagem.crop(box)
The problem is: The getbbox function doesn't work when the document isn't vertical. Since I don't know the angle, how can I rotate the image to use the getbbox funcion? If there's another function that I can use for inclined images instead of getbbox, please tell me.
Thanks for the help.