binarization an image grayscale - python

i am new in python , my probleme it's about edit some changes in an image grayscale , i wanna make a binarization for this image , the values of pixels bigger then 100 take the value 1 (white), and the values low than 100 takes the value 0 (black)
so any suggestion plz (sorry for my bad english)
my code :
`import numpy as np
import cv2
image = cv2.imread('Image3.png', 0)
dimension = image.shape
height = dimension[0]
width = dimension[1]
#finalimage = np.zeros((height, width))
for i in range(height) :
for j in range(width):
if (image[i, j] > 100):
image[i][j] = [1]
else:
image[i][j] = [0]
cv2.imshow('binarizedImage',image)
cv2.waitKey(0)
cv2.destroyAllWindows()

You can try use OpenCV function cv2.threshold for binarize.
import cv2
img = cv2.imread('Image3.png', cv2.IMREAD_GRAYSCALE)
thresh = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)[1]
cv2.imshow('binarizedImage',thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

I think you just want to use np.where():
import numpy as np
image = np.array([[200, 50, 200],[50, 50 ,50],[10, 255, 10]]) #this will be your image instead
In [11]: image
Out[11]:
array([[200, 50, 200],
[ 50, 50, 50],
[ 10, 255, 10]])
In [12]: np.where(image > 100, 1, 0)
Out[12]:
array([[1, 0, 1],
[0, 0, 0],
[0, 1, 0]])

Related

how to mask an image using numpy only

Why this mask layer does not mask image.
import matplotlib.image as mpimg
import numpy
path = 'inp.jpg'
arr = numpy.array(Image.open(path))
img = mpimg.imread(path)
black_pixels_mask = np.all(img == [0, 0, 0], axis=-1)
img[black_pixels_mask] = [255,255,255]
The result img should be the masked one.and the code should replace black to white. Just as a sample colour.
Try this code
arr[numpy.all(arr == [0, 0, 0], axis=-1)]=[255,255,255]
data = Image.fromarray(arr)
data.save(path)

Is there a way to make a square pattern mask that matches the size of my image in python?

I was wondering if there is a way to make an array/column like [255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255....] that repeats until a certain length (length of a imported image) for every row/array. The goal of this will be to make an image that will show 255 as white "pixels" and 0 as the black "pixels". Is this possible?
proposed mask concept
final result
import numpy as np
from skimage import data
from skimage import io
path = r'C:\C:\Python36\bmp_files\slide_3.png'
sz = 400
image = data.astronaut()
patch1 = image[250:250+sz,250:250+sz,:]
patch1.shape
#(48, 48, 3)
mask = np.tile(np.array([[[1],[0]],[[0],[0]]],dtype=np.uint8),(sz/2,sz/2,3))
mask.shape
#(48, 48, 3)
print (mask)
patch2 = patch1 * mask
patch12 = np.hstack((patch1,patch2))`

How to convert binary image to rgba image with transparent background in opencv

Super simple question, I have a single channel image consisting of 0's and 255's and I would like to convert it into a 4 channel image of [0,0,0,0] and [255,255,255,255] in the most efficient manner possible. cv2.COLOR_GRAY2RGBA causes the alpha to all be at 255 and np.where() feels like black magic to me so any help would be appreciated.
One-liner solution using cv2.merge function.
Let your input image be "img" which is of 1 channel.
To convert it to 4 channel, do this:
img = cv2.merge((img.copy(), img.copy(), img.copy(), img.copy()))
Now the "img" will contain 4 channels and all the channels will be the same wrt values.
Just create a numpy array with more layers and then change the values of this array to the values of your image.
img = cv2.imread('img.jpg')
h, w, d = img.shape #(217, 232, 3)
nr_of_new_layers = 1
alpha_img = np.zeros((h, w, d+nr_of_new_layers))
alpha_img[:,:,:3] = img #alpha_img shape = (217, 232, 4)
Or if there isn't any 3rd dimension then you can do
d = 0
img = cv2.imread('img.jpg', d)
h, w = img.shape #(217, 232)
nr_of_new_layers = 4
alpha_img = np.zeros((h, w, d+nr_of_new_layers))
alpha_img[:,:,d] = img #alpha_img shape = (217, 232, 4)
Just stack 4 copies of your single channel image with np.dstack():
RGBA = np.dstack((im,im,im,im)) # or more tersely RGBA = np.dstack(([im]*4))
Example:
import numpy as np
# Make image
im = np.array([0,255,255,0,0], dtype=np.uint8)
Look at it:
array([ 0, 255, 255, 0, 0], dtype=uint8)
Stack it depth-wise with np.dstack():
RGBA = np.dstack((im,im,im,im))
Look at it:
array([[[ 0, 0, 0, 0],
[255, 255, 255, 255],
[255, 255, 255, 255],
[ 0, 0, 0, 0],
[ 0, 0, 0, 0]]], dtype=uint8)

python - opencv morphologyEx remove specific color

After remove captcha's background.
The image remain digits and noise.
Noise line is all in one color : RGB(127,127,127)
And then using morphology method.
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
self.im = cv2.morphologyEx(self.im, cv2.MORPH_CLOSE, kernel)
Some part of digit will be remove.
How to use morphologyEx() remove only color in RGB(127,127,127) ?
In order to eliminate color within a particular range you have to use cv2.inRange() function.
Here is the code:
lower = np.array([126,126,126]) #-- Lower range --
upper = np.array([127,127,127]) #-- Upper range --
mask = cv2.inRange(img, lower, upper)
res = cv2.bitwise_and(img, img, mask= mask) #-- Contains pixels having the gray color--
cv2.imshow('Result',res)
This is what I got for the two images you have:
Image 1:
Image 2:
You carry on from here.
COLOR RANGE
color_dict_HSV = {'black': [[180, 255, 30], [0, 0, 0]],
'white': [[180, 18, 255], [0, 0, 231]],
'red1': [[180, 255, 255], [159, 50, 70]],
'red2': [[9, 255, 255], [0, 50, 70]],
'green': [[89, 255, 255], [36, 50, 70]],
'blue': [[128, 255, 255], [90, 50, 70]],
'yellow': [[35, 255, 255], [25, 50, 70]],
'purple': [[158, 255, 255], [129, 50, 70]],
'orange': [[24, 255, 255], [10, 50, 70]],
'gray': [[180, 18, 230], [0, 0, 40]]}
CREDITS:
Ali Hashemian
HOW TO REMOVE A COLOR FROM YOUR IMAGE USING OPENCV
Since most of you would like to do that, i.e. in my case the task was to remove blue color from the image, I used the following code, to remove blue ink stamps and, blue tick marks from my image in order for proper OCR using Tesseract.
[COLOR REMOVAL] CODE
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# image path:
#path = "D://opencvImages//"
#fileName = "out.jpg"
# Reading an image in default mode:
inputImage = cv2.imread('0.jpg')
# Convert RGB to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Convert the BGR image to HSV:
hsvImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2HSV)
# Create the HSV range for the blue ink:
# [128, 255, 255], [90, 50, 70]
lowerValues = np.array([90, 50, 70])
upperValues = np.array([128, 255, 255])
# Get binary mask of the blue ink:
bluepenMask = cv2.inRange(hsvImage, lowerValues, upperValues)
# Use a little bit of morphology to clean the mask:
# Set kernel (structuring element) size:
kernelSize = 3
# Set morph operation iterations:
opIterations = 1
# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
# Perform closing:
bluepenMask = cv2.morphologyEx(bluepenMask, cv2.MORPH_CLOSE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)
# Add the white mask to the grayscale image:
colorMask = cv2.add(grayscaleImage, bluepenMask)
_, binaryImage = cv2.threshold(colorMask, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imwrite('bwimage.jpg',binaryImage)
thresh, im_bw = cv2.threshold(binaryImage, 210, 230, cv2.THRESH_BINARY)
kernel = np.ones((1, 1), np.uint8)
imgfinal = cv2.dilate(im_bw, kernel=kernel, iterations=1)
cv2.imshow(imgfinal)
BEFORE [Original Image]
Blue Mark Extraction
Final Image
Here you can see that all of the tick marks are almost, removed the reason is that because there is always room for improvement, but this, as it seems, is the best we can get because even removing these little marks is not going to have a profound effect on the OCR using Tesseract.
HOPE THAT HELPS!
Here is my solution.
Your answer is obvious better than my.
def mop_close(self):
def morphological(operator=min):
height, width, _ = self.im.shape
# create empty image
out_im = np.zeros((height,width,3), np.uint8)
out_im.fill(255) # fill with white
for y in range(height):
for x in range(width):
try:
if self.im[y,x][0] ==127 and self.im[y,x][1] ==127 and self.im[y,x][2] ==127:
nlst = neighbours(self.im, y, x)
out_im[y, x] = operator(nlst,key = lambda x:np.mean(x))
else:
out_im[y,x] = self.im[y,x]
except Exception as e:
print(e)
return out_im
def neighbours(pix,y, x):
nlst = []
# search pixels around im[y,x] add them to nlst
for yy in range(y-1,y+1):
for xx in range(x-1,x+1):
try:
nlst.append(pix[yy, xx])
except:
pass
return np.array(nlst)
def erosion(im):
return morphological(min)
def dilation(im):
return morphological(max)
self.im = dilation(self.im)
self.im = erosion(self.im)
final result:

How to pass a numpy ndarray as a color in OpenCV?

I am trying to pass a ndarray into this line: cv2.fillPoly(im, pts=[cnt],color=(centroid_color[0],centroid_color[1],centroid_color[2]))
centroid_color looks like this: [ 0 255 0] and is of type <type 'numpy.ndarray'>
However, I keep getting this error: TypeError: Scalar value for argument 'color' is not numeric.
How would I convert this properly?
edit: my current updated code that still gets the same error:
im = cv2.imread('luffy.jpg')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
contours,h = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
moment = cv2.moments(cnt)
c_y = moment['m10']/(moment['m00']+0.01)
c_x = moment['m01']/(moment['m00']+0.01)
centroid_color = im[c_x,c_y]
centroid_color = np.array((centroid_color[0],centroid_color[1],centroid_color[2]))
r = lambda: random.randint(0,255)
print type(centroid_color)
cv2.fillPoly(im,cnt,centroid_color)
For me the only thing that worked:
self.points = np.int32(np.vstack([
np.random.uniform(0, bounds[1], 3),
np.random.uniform(0, bounds[0], 3)
]).T)
color = np.uint8(np.random.uniform(0, 255, 3))
c = tuple(map(int, color))
cv2.fillPoly(img, [self.points], color=c)
I followed Automaton2000's answer but no luck in OpenCV 4.4.
After tried a thousand times I found that the color param must be passed as list, not np.ndarray. Meanwhile all the other params must be np.ndarray, not list. Well done, OpenCV, for wasting one hour of my time.
import numpy as np
import cv2
pts = np.array([[[10, 40], [70, 16], [100, 90]]], np.int32)
im = np.zeros([240, 320, 3], np.uint8)
# color = np.array((60, 0, 255)) # Not working
color = [60, 0, 255] # This works
cv2.fillPoly(im, pts, color)
cv2.imshow("Ah, opencv", im)
cv2.waitKey(0)
By the way, here's another example for cv2.rectangle
import numpy as np
import cv2
pts = np.concatenate([np.random.randint(0, 120, (10, 2)), np.random.randint(120, 240, (10, 2))], -1)
im = np.zeros([240, 240, 3], np.uint8)
cv2.rectangle(im, tuple(pts[0, :2]), tuple(pts[0, 2:]), [255, 0, 255])
cv2.imshow("Ah, opencv", im)
cv2.waitKey(0)
You can pass a numpy array directly as color argument like this:
import numpy as np
import cv2
pts = np.array([[[10,40], [70,16], [100,90] ]], np.int32)
im = np.zeros([240,320, 3], np.uint8)
color = np.array((60,0,255))
cv2.fillPoly( im, pts, color)
cv2.imshow(" ", im)
cv2.waitKey(1)
Of course it is also possible (though unnecessary) to write it like this:
clr = np.array([255, 0, 128])
cv2.fillPoly( im, pts, color=(clr[0], clr[1], clr[2]))
Edit:
Opencv requires the color argument to be either an array of float or integer type. The type you get from a 3-channel RGB image is probably uint8. Try adding
centroid_color = centroid_color.astype(np.int32, copy=False)
before you pass the color argument to cv2.fillPoly!
The opencv error message is a little confusing here...
color = np.random.randint(low=0, high=256, size=3).tolist()
cv2.rectangle(img, (x, y), (x+w, y+h), color, 3)
Try to use .tolist()
It solved my problem.
You can find usage example on this code.

Categories