opencv-python image processing code-debugging - python

I have written a code in OCV-python for image processing(detection of veins in eye), its not working, can somebody help?
import os,sys
import numpy as np
import scipy
import cv2
import PIL
import Image
import ImageChops
i=cv2.imread('eye.jpg',0);
cv2.imshow(i);
j= cv2.medianBlur(i, 3);
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8));
k= clahe.apply(j);
kernel = np.ones((5,5),np.uint8);
closing = cv2.morphologyEx(k, cv2.MORPH_CLOSE, kernel);
h, w = i.shape[:2];
seed_pt = None;
mask = np.zeros((h+2, w+2), np.uint8);
l=cv2.floodFill(k, mask, seed_pt, (255, 255, 255));
o=ImageChops.difference(closing,l);
(thresh, im_bw) = cv2.threshold(o, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU);
cv2.imshow(im_bw);
'
particularly having problem with reading a .jpg file(it reads a .png file), the imshow() function is not working, and errors are being shown for the imagechops and otsu threshold function.
the matlab code for the above code is(it is working perfectly):
t=('http://www.ohiolionseyeresearch.com/core/files/uploads/2014/03/1217.png');
i=imread(t);
figure, imshow(i)
q=rgb2hsv(i);
t=rgb2gray(i);
figure, imshow(t)
k=medfilt2(t);
figure, imshow(k)
u=adapthisteq(k);
se=strel('disk',10);
c=imclose(u,se);
figure, imshow(c)
d=imfill(u,'holes');
figure, imshow(d)
z=imabsdiff(c,d);
figure, imshow(z)
level=graythresh(z);
BW=im2bw(z,level);
imshow(BW)
'

Related

How to color the circles on a thresholded image in python

I created a code to isolate big circles (white) and I would like to color those circles and create contours on the thresholded image to calculate area.
The thing is the threshold image is a binary image 8uint. How can do that in a binary imagee ?
Thanks for the help
import os
#from skimage import measure, io, img_as_ubyte
from skimage.color import label2rgb, rgb2gray
from skimage.segmentation import clear_border
import matplotlib.pyplot as plt
import numpy as np
import cv2
import pandas as pd
import sys
import glob
original = cv2.imread('D:/2022/Python program/NBC_new2022_/images/image1.jpg',-1)
original = cv2.resize(original, (864, 648)) #resize of original image
img = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
median = cv2.medianBlur(img, 3)
ret, th = cv2.threshold(median, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((9,9), np.uint8)
opening = cv2.morphologyEx(th, cv2.MORPH_OPEN, kernel)
edge_touching_removed = clear_border(opening)
cv2.imshow('original', original)
cv2.imshow("Theshrold image", edge_touching_removed)
cv2.waitKey(0)
cv2.destroyAllWindows()

Numpy array of a png file is rotated in matplotlib.pyplot

I'm trying to scatter all white pixels of this gradient image in matplotlib.pyplot:
import numpy as np
from PIL import Image
import cv2
from matplotlib import pyplot
img = Image.open(
"/root/.../aec.png").convert("L")
img = np.array(img)
kernel = np.ones((2, 2), np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
ox, oy = np.where(gradient == 255)
pyplot.plot(ox, oy, ".k")
pyplot.show()
The original picture (...) has a resolution of 2123x1269 and looks like this:
My graph in pyplot shows my gradient picture 270° rotated clockwise and I don't understand why.
I tried pyplot.plot(oy, ox, ".k"), then it's flipped to the x-axis compared to the original image. Rotating the original image with gradient = cv2.rotate(gradient, cv2.cv2.ROTATE_90_CLOCKWISE) gives me coordinates different from the pixel coordinates of my orginal image. (The x-y-pixel-coordinates have to be the ones of the gradient image.) Also the resolution of 2123x1269 should remain and the program should run as fast as possible.
How can I display the pixel coordinates of the gradient image in matplotlib.pyplot correctly?
That is because origin in opencv is at the top-left. Try reverting y axis on pyplot and exchange x and y.
EDIT: Just use plt.imshow(), it is the right function to display image data.
For anyone who ever encounters this problem, this is my final code:
import numpy as np
from PIL import Image
import cv2
from matplotlib import pyplot
img = Image.open(
"/root/.../aec.png").convert("L")
img = np.array(img)
kernel = np.ones((2, 2), np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
ox, oy = np.where(gradient == 255)
pyplot.plot(oy, ox, ".k")
pyplot.imshow(gradient)
pyplot.show()
Zoomed in version of the plot: correct plot, until now it servers my purpose.
Thanks #frab

Remove background

I am doing OCR to extract information from the ID card. However, accuracy is quite low.
My assumption is that removing the background will make OCR more accurate.
I use the ID scanner machine (link) to obtain the grey image below. It seems that the machine uses IR instead of image processing.
Does anyone knows how to get the same result by using Opencv or tools (photoshop, gimp, etc)?
Thanks in advance.
Here are two more methods: adaptive thresholding and division normalization.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread("green_card.jpg")
# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# do adaptive threshold on gray image
thresh1 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 51, 25)
# write results to disk
cv2.imwrite("green_card_thresh1.jpg", thresh1)
# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (11,11))
morph = cv2.morphologyEx(gray, cv2.MORPH_DILATE, kernel)
# divide gray by morphology image
division = cv2.divide(gray, morph, scale=255)
# threshold
thresh2 = cv2.threshold(division, 0, 255, cv2.THRESH_OTSU )[1]
# write results to disk
cv2.imwrite("green_card_thresh2.jpg", thresh2)
# display it
cv2.imshow("thresh1", thresh1)
cv2.imshow("thresh2", thresh2)
cv2.waitKey(0)
Adaptive Thresholding Result:
Division Normalization Result:
EDIT:
since there are different lighting conditions, contrast adjustment is added here.
The simple approache in my mind to solve your issue is that: since the undesired background colours are Green and Red, and the desired font colour is Black, simply suppress the Red and green colours as following:
import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread, imsave
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu
from skimage import exposure
def adjustContrast(img):
p2, p98 = np.percentile(img, (2, 98))
img_rescale = exposure.rescale_intensity(img, in_range=(p2, p98))
return img_rescale
# Read the image
img = imread('ID_OCR.jpg')
# Contrast Adjustment for each channel
img[:,:,0] = adjustContrast(img[:,:,0]) # R
img[:,:,1] = adjustContrast(img[:,:,1]) # G
img[:,:,2] = adjustContrast(img[:,:,2]) # B
# # Supress unwanted colors
img[img[...,0] > 100] = 255 # R
img[img[...,1] > 100] = 255 # B
# Convert the image to graylevel
img = rgb2gray(img)
# Rescale into 0-255
img = 255*img.astype(np.uint8)
# Save the results
imsave('Result.png', img)
The image will look like:
The Results are not optimal, because also your image resolution isn't high.
At the end, there are many solutions, and improvements, also you can use Morphology to make it look nicer, this is just a simple proposal to solve the problem.

reduce jagged edges and output perfect alphabet

I have a input image:
I am normalising the image and then binarising it using OTSU.
import cv2
import numpy as np
import sys
import os
import time
import imutils
import numpy as np
from matplotlib import pyplot as plt
import re
import math
orgImg = cv2.imread(sys.argv[1])
orgHeight,orgWidth,_ = orgImg.shape
image = imutils.resize(orgImg,height=350)
rheight, rwidth,_= image.shape
kernel = np.ones((7,7), np.uint16)
# image = cv2.erode(image, kernel, iterations=1)
image11 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Copy image to new variable
g = image11.copy()
cv2.normalize(g, g, 70, 255, cv2.NORM_MINMAX)
ret,black_mask = cv2.threshold(g,110,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imshow("image",black_mask)
cv2.imwrite(sys.argv[1]+"thresh.jpg",black_mask)
cv2.waitKey(0)
The output image is:
In the output there are many jagged edges. How do I remove these edges and get a perfect "Ca"?
Output should be something like this:
P.S. Please note that the output image does not necessarily has to be binary
If you leave out the resize with imutils, the result will look like this:
I'm not sure where the extra black lines in your output image come from, because they are not created when I run you're code directly.
I changed around your code and cleaned it up a bit, it now looks like this:
import cv2
import numpy as np
from PIL import Image
orgImg = cv2.imread("ca.png")
image11 = cv2.cvtColor(orgImg, cv2.COLOR_BGR2GRAY)
cv2.normalize(image11, image11, 70, 255, cv2.NORM_MINMAX)
ret, black_mask = cv2.threshold(image11, 110, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow("Original image", orgImg)
cv2.imshow("Final image", black_mask)
cv2.waitKey(0)
cv2.imwrite("ca_blackmask.png", black_mask)

Can't display a normal image in matplotlib, it keeps displaying with the jet colormap

I have code that displays the MISER regions of an image:
import numpy as np
import cv2
import sys
import matplotlib.pyplot as plt
imp1 = sys.argv[1]
img1 = cv2.imread(imp1)
mser = cv2.MSER()
gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
vis = img1.copy()
regions = mser.detect(gray, None)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(vis, hulls, 1, (0, 255, 0))
def plot_stuff(img1, img1_name, img2, img2_name):
fig,axes = plt.subplots(1,2,figsize=(15,6))
axes[0].imshow(img1, cmap='Greys_r')
axes[0].set_title(img1_name)
axes[1].imshow(img2)
axes[1].set_title(img2_name)
fig.suptitle("All Images")
plt.show()
plot_stuff(img1, 'Original', vis, 'MISER Regions')
And it works fine, except it's blue:
And that's where I got stuck. Because no matter what I do, I can't get it to show the Image as gray, and the MISER lines as green. It keeps returning jet:
Even when I show just the image, it still returns jet. Why isn't there an RGB colormap? Better yet, why does there have to be a colormap at all, why can't it just show the normal image?
You data is stored as 64 bit numpy arrays, from the docs,
For RGB and RGBA images, matplotlib supports float32 and uint8 data types
You either need it in this format or need to specify a colormap. It seems the other issue is that 'cv2.polylines' returns an images, which means you cannot set the colours of the lines and the background separately. A solution to this is to use a blank transparent image of the same size to draw the mser (MISER!?) curves and then plot them both on the same axis,
import numpy as np
import cv2
import sys
import matplotlib.pyplot as plt
imp1 = sys.argv[1]
img1 = cv2.imread(imp1)
mser = cv2.MSER()
gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
vis = np.zeros([img1.shape[0],img1.shape[1],4])
regions = mser.detect(gray, None)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(vis, hulls, 1, (0, 255, 0))
vis = np.array(vis, dtype=np.uint8)
#Copy green channel data to (alpha) transparent channel
vis[:,:,3] = vis[:,:,1]
def plot_stuff(img1, img1_name, img2, img2_name):
fig,axes = plt.subplots(1,2,figsize=(15,6))
print(img1.shape)
axes[0].imshow(np.sum(img1,2), cmap='Greys_r')
axes[0].set_title(img1_name)
axes[1].imshow(np.sum(img1,2), cmap='Greys_r')
axes[1].imshow(img2)
axes[1].set_title(img2_name)
fig.suptitle("All Images")
plt.show()
plot_stuff(img1, 'Original', vis, 'MISER Regions')
which for me returns,
using matplotlib.version 1.4.3' and cv2.version'$Rev: 4557 $'
The imshow docs says that cmap is ignored when image has RGB information.
You can consider creating a gray level image
newimg = numpy.sum(img, 2)
Then
ax.imshow(newimg, cmap='gray')

Categories

Resources