Related
I've been experimenting with pytesseract and I have searched some improvements for accuracy but it didn't work for me. So here's my img:
This is the output:
Code:
img = cv2.imread("temp.png")
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thr = cv2.adaptiveThreshold(gry, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 4)
txt = pytesseract.image_to_string(thr, config='--psm 13')
print(txt) # "#)"
I don't know everything since I just started, can someone give me tips how can this be done?
Edit: Ahx solved my question but there's something buggy in the code. It's reading 6 as é. For example d6, it will read it as dé.
I added some thresholds and blurs because I think it will improve it but it didn't.
Here's my updated code:
img = cv2.imread('temp.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lwr = np.array([0, 0, 0])
upr = np.array([179, 255, 180])
msk = cv2.inRange(hsv, lwr, upr)
msk = cv2.resize(msk, (0, 0), fx=3, fy=3, interpolation=cv2.INTER_CUBIC)
msk = cv2.adaptiveThreshold(cv2.bilateralFilter(msk, 9, 75, 75), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
msk = cv2.adaptiveThreshold(cv2.medianBlur(msk, 3), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
txt = pytesseract.image_to_string(msk, lang='eng', config=r'--psm 6 --oem 3')
The e6 actually worked but 6 in others like d6, Nf6 is always é.
Here's an example if ever you wanna try it out:
Output:
result: Nf6é
You can easily get the result by performing color-segmentation. First, you need to load the image, convert it to the HSV format. Next, define the upper and lower boundaries to get the binary-mask. The binary mask will contain the required features for recognizing the characters. Then we will upsample the binary-mask and give input to the tesseract.
Upsampled Binary-mask
OCR Result: e6
Code:
import cv2
import numpy as np
import pytesseract
# Load the image
img = cv2.imread("iTO9h.png")
# Convert to grayscale
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Get binary-mask
lwr = np.array([0, 0, 0])
upr = np.array([179, 255, 180])
msk = cv2.inRange(hsv, lwr, upr)
# Up-sample
msk = cv2.resize(msk, (0, 0), fx=2, fy=2)
# OCR
txt = pytesseract.image_to_string(msk)
print(txt)
I have an image that has green borders which encapsulates the items that has to be deleted.
I have filtered the only green part of the image so my next step is to fill inside of the filtered contour with a different color then I will remove that part from the image? I am very open the any suggestions.
Here is my code
import cv2
import numpy as np
import imageio
## Read
img = cv2.imread("test.png",-1)
img2 = imageio.imread("test.png")
## convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
## mask of green (36,25,25) ~ (86, 255,255)
# mask = cv2.inRange(hsv, (36, 25, 25), (86, 255,255))
mask = cv2.inRange(hsv, (36, 25, 25), (70, 255,255))
## slice the green
imask = mask>0
green = np.zeros_like(img, np.uint8)
green[imask] = img[imask]
green_filter=img[100,100,0]
print(green_filter)
## save
cv2.imshow('image', green)
cv2.imshow(' ',img)
cv2.waitKey(0)
print(img)
print(green)
image i have: https://ibb.co/vJX1jM4
image i reached currently:https://ibb.co/FnScYHc
import cv2
import numpy as np
import matplotlib.pyplot as plt
import imageio
## Read
img = cv2.imread("test.png",-1)
## convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (36, 25, 25), (70, 255,255))
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
idx = 0
mask1 = np.zeros_like(img)
cv2.drawContours(mask1, contours, idx, (255,255,255), -1)
out = np.zeros_like(img)
out[mask1 == (255,255,255)] = img[mask1 == 255]
fig, axs = plt.subplots(1, 3, figsize=(16, 4))
for ax, image in zip(axs, ['img', 'mask1', 'out']):
ax.imshow(eval(image))
ax.set_title(image)
ax.grid(True)
plt.show()
=>
I let you play around with this snippet, especially if you want to remove your green contour.
If you want to reverse the kept area, you need to replace:
out[mask1 == (255,255,255)] = img[mask1 == 255]
by:
out[mask1 == (0,0,0)] = img[mask1 == 0]
(see second figure below)
I just imported matplotlib for convenience here.
Sorry for the quick and dirty sudo code here, but this is generally how you would go about it.
Load in image
Convert to grayscale
Find Contours
Find the index of the contour you want to fill
Use fillConvexPoly to fill the specific contour with the index found above.
Here is some code that can guide you in the right direction.
#Read in the image
img = cv2.imread("test.png")
#Convert to grayscale
grayImg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Find contours
contours = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#Find contour index that you want
#I didn't put code here because I don't know what index would work for your image,
#But you can manually find it by just drawing each contour found one by one until
#You get the contour you want, then use that index to fill it.
#Fill the contour
#NOTE: You will have to adjust this function for your own code
cv2.fillConvexPoly(img, contours[index], lineType=8, shift=0)
I know here already some questions were asked but they did't help me to solve my problem. I will appreciate any help to solve my problem.
I'm new to opencv.
I have an image and apply some code to get contours from image. Now i want to get the RGB color values from detected contours. How can i do that?
I do research on it and find that it could be solved by using contours so i try to implement contours and now finally i want to get the color values of the contours.
Here is my Code:
import cv2
import numpy as np
img = cv2.imread('C:/Users/Rizwan/Desktop/example_strip1.jpg')
img_hsv = cv2.cvtColor(255-img, cv2.COLOR_BGR2HSV)
lower_red = np.array([40, 20, 0])
upper_red = np.array([95, 255, 255])
mask = cv2.inRange(img_hsv, lower_red, upper_red)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
color_detected_img = cv2.bitwise_and(img, img, mask=mask)
print(len(contours))
for c in contours:
area = cv2.contourArea(c)
x, y, w, h = cv2.boundingRect(c)
ax = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 0), 2)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(color_detected_img, [box], -1, (255, 0, 0), 2)
cv2.imshow("Cropped", color_detected_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
I expect the output should be the RGB values of the detected color inside the contours.
As asked in the comments, here's a possible solution to extract the BGR(!) values from the pixels of an image inside a before found contour. The proper detecting of the desired, colored stripes is omitted here as also discussed in the comments.
Having an image and a filled mask of a contour, for example from cv2.drawContours, we can simply use NumPy's boolean array indexing by converting the (most likely uint8) mask to an bool_ array.
Here's a short code snippet, that uses NumPy's savetxt to store all values in some txt file:
import cv2
import numpy as np
# Some dummy image
img = np.zeros((100, 100, 3), np.uint8)
img = cv2.rectangle(img, (0, 0), (49, 99), (255, 0, 0), cv2.FILLED)
img = cv2.rectangle(img, (50, 0), (99, 49), (0, 255, 0), cv2.FILLED)
img = cv2.rectangle(img, (50, 50), (99, 99), (0, 0, 255), cv2.FILLED)
# Mask of some dummy contour
mask = np.zeros((100, 100), np.uint8)
mask = cv2.fillPoly(mask, np.array([[[20, 20], [30, 70], [70, 50], [20, 20]]]), 255)
# Show only for visualization purposes
cv2.imshow('img', img)
cv2.imshow('mask', mask)
# Convert mask to boolean array
mask = np.bool_(mask)
# Use boolean array indexing to get all BGR values from img within mask
values = img[mask]
# For example, save values to txt file
np.savetxt('values.txt', values)
cv2.waitKey(0)
cv2.destroyAllWindows()
The dummy image looks like this:
The dummy contour mask looke like this:
The resulting values.txt has some >1000 entries, please check yourself. Attention: Values are BGR values; e.g. prior converting the image to RGB is needed to get RGB values.
Hope that helps!
I've detected contours for an image using opencv python,now I should blackout the image outside the contour.Could anyone help me to do this?
Given your found contours, use drawContours to create a binary mask, in which your contours are filled. Dependent on how you do that (black image, white contours vs. white image, black contours), you set all pixels in your input image to 0 expect for the masked (or unmasked) ones. See the following code snippet for a visualization:
import cv2
import numpy as np
# Artificial input
input = np.uint8(128 * np.ones((200, 100, 3)))
cv2.rectangle(input, (10, 10), (40, 60), (255, 240, 172), cv2.FILLED)
cv2.circle(input, (70, 100), 20, (172, 172, 255), cv2.FILLED)
# Input to grayscale
gray = cv2.cvtColor(input, cv2.COLOR_RGB2GRAY)
# Simple binary threshold
_, gray = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)
# Find contours
cnts, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Generate mask
mask = np.ones(gray.shape)
mask = cv2.drawContours(mask, cnts, -1, 0, cv2.FILLED)
# Generate output
output = input.copy()
output[mask.astype(np.bool), :] = 0
cv2.imwrite("images/input.png", input)
cv2.imwrite("images/mask.png", np.uint8(255 * mask))
cv2.imwrite("images/output.png", output)
The artificial input image:
The mask generated during processing:
The final output:
I have an image. Like this:
I detect a subject(which is a person in this case) & it masks the image like this:
I want the background of the subject to be blurrred. Like this:
Below is the code I have tried. the following code only blurs
import cv2
import numpy as np
from matplotlib import pyplot as plt
import os
path = 'selfies\\'
selfImgs = os.listdir(path)
for image in selfImgs:
img = cv2.imread(path+image)
img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur = cv2.blur(img,(10,10))
#canny = cv2.Canny(blur, 10, 30)
#plt.imshow(canny)
plt.imshow(blur)
j=cv2.cvtColor(blur, cv2.COLOR_BGR2RGB)
print(image)
cv2.imwrite('blurred\\'+image+".jpg",j)
Is there any way by which I can blur only specific part/parts of the image.
This project is based on https://github.com/matterport/Mask_RCNN
I can provide more information if required.
I have an approach in numpy :-
final_image = original * mask + blurred * (1-mask)
You may use np.where() method to select the pixels where you want blurred values and then replace them as:
import cv2
import numpy as np
img = cv2.imread("/home/user/Downloads/lena.png")
blurred_img = cv2.GaussianBlur(img, (21, 21), 0)
mask = np.zeros((512, 512, 3), dtype=np.uint8)
mask = cv2.circle(mask, (258, 258), 100, np.array([255, 255, 255]), -1)
out = np.where(mask==np.array([255, 255, 255]), img, blurred_img)
cv2.imwrite("./out.png", out)
As ZdaR said:
import cv2
import numpy as np
img = cv2.imread("/home/user/Downloads/lena.png")
blurred_img = cv2.GaussianBlur(img, (21, 21), 0)
mask = np.zeros((512, 512, 3), dtype=np.uint8)
mask = cv2.circle(mask, (258, 258), 100, np.array([255, 255, 255]), -1)
out = np.where(mask==np.array([255, 255, 255]), img, blurred_img)
cv2.imwrite("./out.png", out)
This is good idea but I've got same error as penta:
#ZdaR I get TypeError: Scalar value for argument 'color' is not numeric
A simple solution is to modify color value when you create Circle:
mask = cv2.circle(mask, (258, 258), 100, (255, 255,255), -1)
just CHANGE np.array([255,255,255]) to (255,255,255).
I don't know what tools you use for subject detection, but if you have a way to copy the subject, you can first copy the whole image and then blur it. finally, you can copy the subject on the blurred image.
if it gives false and true on pixels in oppose to giving borders, you can just bitwise it.