I was trying to generate some bar-code (using python-barcode) with product info I successfully generate bar-code but Not to remove under code and write my own text
My code:
import barcode
from barcode.writer import ImageWriter
barCode = "00000016901011900000"
barCodeImage = barcode.get('Code128', barCode, writer=ImageWriter())
barCodeImage.save("one")
Which gives me this barcode
But I want to remove that showing number under the bar-code and write some text (as product info or name)
Here's a method using OpenCV
Convert image to grayscale
Otsu's threshold to obtain binary image
Dilate to connect contour
Find contours and filter using contour area
Replace ROI with desired text
After converting to grayscale, we Otsu's threshold to get a binary image
Now we dilate to connect the contours
From here we find contours and sort using contour area. The smaller contour will be the ROI of the number. Here's the detected number ROI
Now we "erase" the number by coloring in the ROI with white and write our desired text with cv2.putText(). Here's the result
import cv2
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea)
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
image[y:y+h, x:x+w] = [255,255,255]
cv2.putText(image, 'Super Spicy Example Text', (x,y), \
cv2.FONT_HERSHEY_SIMPLEX, .6, (0,0,0), 1)
break
cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('image', image)
cv2.waitKey(0)
Use this:
barCodeImage.save("one", text="Put your text here")
You can also use this with the writer:
barCodeImage.write(buffer, text="Put your text here")
Source: https://github.com/WhyNotHugo/python-barcode/blob/722d45eb3f3fe01da23155ddb0856ee0916cddf4/barcode/base.py#L56
Related
I have a hyperspectral image. In each image, there are many objects. I have to segment, crop, and save them as separate images. The segmented image after applying the thresholding is as below:
The problem is that I have to crop the segmented objects and save them. How it can be done?
Here's a simple approach:
Obtain binary image. Load the image, convert to grayscale, and Otsu's threshold to obtain a binary image.
Remove noise. We morphological operations to remove any particles of noise in the image.
Extract objects. From here we find contours, obtain each bounding rectangle then extract and save each ROI using Numpy slicing.
Detected objects
Saved ROIs
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Morph open to remove noise
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
# Find contours, obtain bounding box, extract and save ROI
ROI_number = 0
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
ROI = original[y:y+h, x:x+w]
cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
ROI_number += 1
cv2.imshow('image', image)
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.waitKey()
I want to detect and then extract letters and numbers from this image. I have just started to learn OpenCV and I think that this can be done with that lib. You have the image that I used and desired output below.
This is the code that I have:
import cv2
# read original image
img = cv2.imread('image.jpg')
cv2.imshow('original', img)
cv2.waitKey(0)
# convert it to gray and apply filter
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert to grey scale
gray = cv2.bilateralFilter(gray, 11, 17, 17)
cv2.imshow('gray', gray)
cv2.waitKey(0)
#apply treshold
thresh = cv2.threshold(gray, 10, 255, cv2.THRESH_OTSU)[1]
cv2.imshow('thresh', thresh)
cv2.waitKey(0)
This is the image:
My goal is to get separated images of each letter and number (I did this in paint):
So, what should I do to get this?
It would be perfect to keep the same order of letters and numbers, for example:
MXF51051
Here's an approach using simple thresholding + contour filtering
Convert image to grayscale and Otsu's threshold
Find contours and filter using contour area
Extract and save ROI
We begin by converting to grayscale and then Otsu's threshold to obtain a binary image
Next we find contours using cv2.findContours(). To keep the same order of letters/numbers, we use imutils.contours.sort_contours() with the left-to-right parameter to ensure that when we iterate through the contours, we have each contour in the correct order. For each contour, we filter using a minimum and maximum area threshold to ensure that we only keep contours with the desired text. Once we have the filtered ROI, we extract/save the ROI using Numpy slicing. Here's the filtered mask with only the desired text
Detected numbers and letters
The extracted ROIs in the correct order
import cv2
import numpy as np
from imutils import contours
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="left-to-right")
ROI_number = 0
for c in cnts:
area = cv2.contourArea(c)
if area < 800 and area > 200:
x,y,w,h = cv2.boundingRect(c)
ROI = 255 - thresh[y:y+h, x:x+w]
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
ROI_number += 1
cv2.imshow('mask', mask)
cv2.imshow('thresh', thresh)
cv2.waitKey()
Right now I am trying to create one program, which remove text from background but I am facing a lot of problem going through it
My approach is to use pytesseract to get text boxes and once I get boxes, I use cv2.inpaint to paint it and remove text from there. In short:
d = pytesseract.image_to_data(img, output_type=Output.DICT) # Get text
n_boxes = len(d['level']) # get boxes
for i in range(n_boxes): # Looping through boxes
# Get coordinates
(x, y, w, h) = (d['left'][i], d['top'][i], d['width'][i], d['height'][i])
crop_img = img[y:y+h, x:x+w] # Crop image
gray = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)
gray = inverte(gray) # Inverse it
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)[1]
dst = cv2.inpaint(crop_img, thresh, 10, cv2.INPAINT_TELEA) # Then Inpaint
img[y:y+h, x:x+w] = dst # Place back cropped image back to the source image
Now the problem is that I am not able to remove text completely
Image:
Now I am not sure what other method I can use to remove text from image, I am new to this that's why I am facing problem. Any help is much appreciated
Note: Image looks stretched because I resized it to show it in screen size
Original Image:
Here's an approach using morphological operations + contour filtering
Convert image to grayscale
Otsu's threshold to obtain a binary image
Perform morph close to connect words into a single contour
Dilate to ensure that all bits of text are contained in the contour
Find contours and filter using contour area
Remove text by "filling" in the contour rectangle with the background color
I used chrome developer tools to determine the background color of the image which was (222,228,251). If you want to dynamically determine the background color, you could try finding the dominant color using k-means. Here's the result
import cv2
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, close_kernel, iterations=1)
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,3))
dilate = cv2.dilate(close, dilate_kernel, iterations=1)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > 800 and area < 15000:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (222,228,251), -1)
cv2.imshow('image', image)
cv2.waitKey()
I have this image and I´m trying to count how many white "balls" there are
I´m trying this code below and get this result
import cv2
import numpy as np
img = cv2.imread('MASK.jpg', cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img,(700,700))
img = cv2.subtract(255, img)
detector = cv2.SimpleBlobDetector_create()
# Detect the blobs in the image
keypoints = detector.detect(img)
print(len(keypoints))
imgKeyPoints = cv2.drawKeypoints(img, keypoints, np.array([]), (0,0,255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("Keypoints", imgKeyPoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
Some preprocessing to isolate the blobs become counting them can help. Here's an approach:
Convert image to grayscale
Otsu's threshold
Morph open to remove noise
Find contours and sum blobs
After converting to grayscale, we Otsu's threshold to get a binary image
Next we morph close with a cv2.MORPH_ELLIPSE kernel to remove noise and separate the blobs better
Next we find contours and sum the blobs. Note the morph close did not "detach" all the connected blobs, so we filter using contour area. If the blob is greater than some minimum threshold, we count the blob as a double instead of a single. Here's the detected blobs
Result
blobs: 325
import cv2
import numpy as np
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=5)
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
blobs = 0
for c in cnts:
area = cv2.contourArea(c)
cv2.drawContours(mask, [c], -1, (36,255,12), -1)
if area > 13000:
blobs += 2
else:
blobs += 1
print('blobs:', blobs)
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.imshow('mask', mask)
cv2.waitKey()
I am trying to make the background of the square headers (The black bar that contains TERMS PONUMBER PROJECT) white and the text within black.
I have tried using the findContours method to find the contours and then crop and invert them so that I get them in the black text and white background form. But the problem is I am not having any idea on how to proceed ahead or is there any better approach to this
image =cv2.imread("default.jpg")
gray=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
th, thresh = cv2.threshold(gray,1, 255, cv2.THRESH_BINARY_INV)
kernel = cv2.getStructuringElemnt(cv2.MORPH_ELLIPSE,(7,7))
morp_image = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
contours = cv2.findContours(morp_image,
cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
cnts = sorted(contours,key=cv2.contourArea)[-1]
The code above does find each such contour on an individual basis like if I change the [-1] in the last line of the code to [-2], it will find the next contour but I want to find all such areas in the image in a single go and make the background of such areas white while changing the text to black.
Thanks
Here's a simple approach
Convert image to grayscale and Gaussian blur
Otsu's threshold to obtain binary image
Find contours
Filter using the number of corners and contour area
Extract ROI, invert ROI, and replace into original image
The idea is that if the contour has 4 corners, it must be a square/rectangle. In addition, we filter using a minimum contour area to ignore noise. If the contour passes our filter then we have a desired ROI to invert. The detected ROIs
Now we extract each ROI using Numpy slicing. Here's each ROI before and after inverting
Now we simply replace each inverted ROI back into the original image to get our result
import cv2
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.015 * peri, True)
area = cv2.contourArea(c)
if len(approx) == 4 and area > 1000:
x,y,w,h = cv2.boundingRect(c)
ROI = 255 - image[y:y+h,x:x+w]
image[y:y+h, x:x+w] = ROI
cv2.imshow('image', image)
cv2.imwrite('image.png', image)
cv2.waitKey()