How to convert a range of gray pixels to black with opencv? - python

I am working with OpenCV and Tesseract. I was trying to convert a range of grey pixels to black. Example:
As you can see there is a "bright" multiple grey color, I need to convert that to full black for OCR to be able to read it better.
Does anyone know how to do so?

import cv2
import numpy as np I = cv2.imread('imgPath')
## If you are interested in thresholding based on brightness,
## using grey channel or brightness channel from HSV is always a good idea :)
# Convert input RGB to HSV
HSV = cv2.cvtColor(I, cv2.COLOR_BGR2HSV)
# Get brightness channel
V = HSV[:, :, 2]
# Threshold all the very bright pixels
bw = 255*np.uint8(V < 200)
# save the image you want
cv2.imwrite("bw.png", bw)

Related

How can I use thresholding to improve image quality after rotating an image with skimage.transform?

I have the following image:
Initial Image
I am using the following code the rotate the image:
from skimage.transform import rotate
image = cv2.imread('122.png')
rotated = rotate(image,34,cval=1,resize = True)
Once I execute this code, I receive the following image:
Rotated Image
To eliminate the blur on the image, I use the following code to set a threshold. Anything that is not white is turned to black (so the gray spots turn black). The code for that is as follows:
ret, thresh_hold = cv2.threshold(rotated, 0, 100, cv2.THRESH_BINARY)
plt.imshow(thresh_hold)
Instead of getting a nice clear picture, I receive the following:
Choppy Image
Does anyone know what I can do to improve the image quality, or adjust the threshold to create a clearer image?
I attempted to adjust the threshold to different values, but this changed the image to all black or all white.
One way to approach that is to simply antialias the image in Python/OpenCV.
To do that one simply converts to grayscale. Then blurs the image, then applies a stretch of the image.
Adjust the blur sigma to change the antialiasing.
Input:
import cv2
import numpy as np
import skimage.exposure
# load image
img = cv2.imread('122.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# blur threshold image
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=2, sigmaY=2, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
result = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.uint8)
# save output
cv2.imwrite('122_antialiased.png', result)
# Display various images to see the steps
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:

How to draw an overlay that matches the shape of an image with a transparent background using OpenCV?

I have an image like this:
The image is transparent. I want to apply a red overlay just on the letters of the logo. I have experience with cv2.addWeight(...) but I always work on that using cv2.rectangle(...). Is there a way I can add a red overlay just on the shape of the image?
As you didn't answer my question in the comments, I am guessing what you want from the answer you have accepted.
You can do what you appear to want by simply adding a solid red overlay with weighting to the BGR channels only, without touching the alpha channel like this:
import cv2
import numpy as np
# Load image including alpha channel
img = cv2.imread('google.png', cv2.IMREAD_UNCHANGED)
# Make a solid red overlay same height and width as original but without alpha channel
redOverlay = np.full_like(img[:,:,0:3], (0,0,255))
# Add overlay to BGR channels leaving alpha unaffected and save result
img[..., 0:3] = cv2.addWeighted(img[..., 0:3], 0.7, redOverlay, 0.3, 0)
cv2.imwrite('result.png', img)
The alpha channel controls the transparent areas. So copying the alpha channel to the red channel should give a red overlay on the non-transparent areas. The IMREAD_UNCHANGED flag allows the reading of the signal without OpenCV removing the alpha (fourth channel).
import cv2
import numpy as np;
img = cv2.imread('test.png', cv2.IMREAD_UNCHANGED)
alpha = img[:,:,3];
imgz = np.zeros(img.shape, dtype=np.uint8)
imgz[:,:,2] = alpha;
imgz[:,:,3] = alpha;
dst = cv2.addWeighted(img, 0.7, imgz, 0.3, 0)
cv2.imwrite('test2.png', dst);
cv2.imshow("original", img)
cv2.imshow("alhpa", alpha)
cv2.imshow("final", dst)
cv2.waitKey(0)

How to auto adjust contrast and brightness of a scanned Image with opencv python

I want to auto adjust the brightness and contrast of a color image taken from phone under different lighting conditions. Please help me I am new to OpenCV.
Source:
Input Image
Result:
result
What I am looking for is more of a localized transformation. In essence, I want the shadow to get as light as possible completely gone if possible and get darker pixels of the image to get darker, more in contrast and the light pixels to get more white but not to a point where it gets overexposed or anything like that.
I have tried CLAHE, Histogram Equalization, Binary Thresholding, Adaptive Thresholding, etc But nothing has worked.
My initials thoughts are that I need to neutralize Highlights and bring darker pixels more towards the average value while keeping the text and lines as dark as possible. And then maybe do a contrast filter. But I am unable to Get the result please help me.
Here is one way to do that in Python/OpenCV.
Read the input
Increase contrast
Convert original to grayscale
Adaptive threshold
Use the thresholded image to make the background white on the contrast increased image
Save results
Input:
import cv2
import numpy as np
# read image
img = cv2.imread("math_diagram.jpg")
# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# do adaptive threshold on gray image
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 21, 15)
# make background of input white where thresh is white
result = img.copy()
result[thresh==255] = (255,255,255)
# write results to disk
cv2.imwrite("math_diagram_threshold.jpg", thresh)
cv2.imwrite("math_diagram_processed.jpg", result)
# display it
cv2.imshow("THRESHOLD", thresh)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
Threshold image:
Result:
You can use any local binarization method. In OpenCV there is one such method called Wolf-Julion local binarization which can be applied to the input image. Below is code snippet as an example:
import cv2
image = cv2.imread('input.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)[:,:,2]
T = cv2.ximgproc.niBlackThreshold(gray, maxValue=255, type=cv2.THRESH_BINARY_INV, blockSize=81, k=0.1, binarizationMethod=cv2.ximgproc.BINARIZATION_WOLF)
grayb = (gray > T).astype("uint8") * 255
cv2.imshow("Binary", grayb)
cv2.waitKey(0)
The output result from above code is below. Please note that to use ximgproc module you need to install opencv contrib package.

How to find various colours from image without giving range of colour

I need to separate yellow colour from this image. I tried with opencv cv2.inrange and thresholding but it didn't give satisfactory results. Whenever lighting conditions change shade of colour will change so please suggest any other algorithm.
Here is where HSV value system plays a role. The normal rgb value filtering can give different results in different lighting conditions. But, HSV can help you to select only the specific color less susceptible to ligthing conditions .
image=cv2.imread('image.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_yellow = np.array([20,100,100])
upper_yellow = np.array([30,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(image,image, mask= mask)
cv2.imshow('res',res)
#press any key to quit
cv2.waitKey(0)
cv2.destroyAllWindows()
You can learn more about hsv and its applications here,
https://www.kirupa.com/design/little_about_color_hsv_rgb.htm
https://docs.opencv.org/3.4.2/df/d9d/tutorial_py_colorspaces.html
http://aishack.in/tutorials/tracking-colored-objects-opencv/
# I tried with code
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
threshold=0.667
#load image
img=plt.imread(r'C:\Users\Desktop\pbr\artik image\pbr2.jpg')
#extract each color channel
red, green, blue=img[:,:,0],img[:,:,1],img[:,:,2]
#total red+green+biue intensity
intensity=img.sum(axis=2)
add2=np.sum(intensity)
#function to calculate proportion of a certain channel
def color_frac(color):
return np.sum(color)/np.sum(intensity)
#calculate proportion of each color
red_fraction=color_frac(red)
green_fraction=color_frac(green)
blue_fraction=color_frac(blue)
sum_color_fraction=red_fraction+green_fraction+blue_fraction
print('Red fraction:{}'.format(red_fraction))
print('\nGreen fraction:{}'.format(green_fraction))
print('\nBlue fraction:{}'.format(blue_fraction))
print('\nRGB sum:{}'.format(sum_color_fraction))
print(red.shape==green.shape==blue.shape)
add1=red_fraction+green_fraction
green1=green.astype(float)
red1=red.astype(float)
yellow=green1+red1
check=yellow/intensity
j=check
df=pd.DataFrame.from_records(check)
Bad=df[df>threshold].count().sum()
df[df>threshold]=1
df[df<=threshold]=0
df=df.fillna(1)
data=df*255
data=df.astype(np.uint8)
plt.imshow(data)
#plt.imshow(green)
#plr.imshow(red+green)

Detecting Colors on object in OpenCV - Python

I am having an issue with color detection in OpenCV 3.4. I will present a picture of my problem below.
import numpy as np
import cv2
img= cv2.imread("C:\\Users\Stefan_Cepa\\Desktop\\dataset2\\set\\A6.png")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_range = np.array([30,150,150])
upper_range = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_range, upper_range)
output = cv2.bitwise_and(img, img, mask = mask)
cv2.imshow("images", np.hstack([img, output]))
cv2.imshow('mask', mask)
while(True):
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
As you can see I've set my lower and upper bounds to detect Red color in an image, but for some reason, as you can see in image below, I am not getting any results. Any tips & tricks would be extremely helpful! Thank you in advance!
You are using the hsv colorspace but you are providing ranges of bgr values. they are incompatible.
For hsv:
For HSV, Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255]. Different softwares use different scales. So if you are comparing OpenCV values with them, you need to normalize these ranges.
source: docs.opencv.org/3.2.0
Your code almost looks like this: http://pyimagesearch.com/2014/08/04/opencv-python-color-detection. Only they use bgr.
Solution:
Convert your mask-ranges to hsv or load images as bgr.
Red on hsv is on hue 0 so you probably would need a combined mask of 170-180 hue and 0-10 hue.

Categories

Resources