Reputation: 13
I am trying to solve the issue of creating paths around logos with OpenCV. I have attached two images, tekst.png and tekst2.png. I have also attached an image comparison.png that shows the wanted result (created manually) and the result I currently am getting with my program.
If anyone has any tips for me, I'd appreciate it a lot!
Short description of wanted solution:
The code I currently have:
def current_milli_time():
return round(time.time() * 1000)
def time_calculation_start():
timing.append(current_milli_time())
def time_calculation_end(string):
timing.append(current_milli_time())
print(str(string) + ": ", timing[1] - timing[0], "ms")
timing.clear()
def render_png(filename):
print(filename)
time_calculation_start()
original_image = cv2.imread(str(filename), cv2.IMREAD_UNCHANGED)
copy = original_image.copy() # Saved for imagecreation
time_calculation_end("Setup")
time_calculation_start()
if(original_image.shape[2] == 4):
b,g,r,mask = cv2.split(original_image)
time_calculation_end("Mask")
# Reduce outer turdss
time_calculation_start()
kernel = np.ones((3,3), np.uint8)
dilation = cv2.dilate(mask,kernel,iterations = 2)
dilation = cv2.erode(dilation,kernel,iterations = 1)
time_calculation_end("Dialtion")
time_calculation_start()
gaublur = cv2.GaussianBlur(dilation,(16,16),0)
time_calculation_end("Gaussian blur")
#Find contours
time_calculation_start()
contours, hierarchy = cv2.findContours(gaublur, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
time_calculation_end("Find contours")
print("\tContour layers: ", len(contours))
# Draw contours
time_calculation_start()
cv2.drawContours(copy, contours, -1, (0, 255, 0, 255),1)
time_calculation_end("Draw contours")
print("\n")
cv2.imwrite(str(render_path) + str(filename), copy)
Upvotes: 1
Views: 5909
Reputation: 53164
Here is the alternate method to deal with your other image in Python/OpenCV. Basically we substitute a Gaussian blur and threshold for the dilation. Use the first Gaussian blur sigmas to change the thickness of the white and the second Gaussian blur sigmas to change the thickness of the shadow. Typically, about 3*sigma=thickness in pixels. Or you can use the size arguments for a direct change of thickness in pixels and set the sigmas to 0.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('10years.png', cv2.IMREAD_UNCHANGED)
# extract bgr image
bgr = img[:,:,0:3]
# extract alpha channel
alpha = img[:,:,3]
# blur alpha channel to smooth features (in place of dilation)
blurred = cv2.GaussianBlur(alpha, (0,0), sigmaX=5, sigmaY=5, borderType = cv2.BORDER_DEFAULT)
# threshold near 0 (in place of dilation)
thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY)[1]
# make edge outline
edge = cv2.Canny(thresh, 0, 200)
# thicken edge
edge = cv2.GaussianBlur(edge, (0,0), sigmaX=0.3, sigmaY=0.3)
# make background
result = np.full_like(bgr, (255,255,255))
# invert threshold image and blur to thresh
thresh_inv = 255 - thresh
thresh_inv = cv2.GaussianBlur(thresh_inv, (0,0), sigmaX=21, sigmaY=21)
thresh_inv = cv2.merge([thresh_inv,thresh_inv,thresh_inv])
# overlay blurred area on background
result[thresh_inv>0] = thresh_inv[thresh_inv>0]
# overlay threshold white region
result[thresh==255] = (255,255,255)
# overlay bgr image
result[thresh==255] = bgr[thresh==255]
# overlay edge
result[edge!=0] = (96,96,96)
# save resulting images
cv2.imwrite('10years_alpha.jpg',alpha)
cv2.imwrite('10years_alpha_thresh.jpg',thresh)
cv2.imwrite('10years_alpha_thresh_inv.jpg',thresh_inv)
cv2.imwrite('10years_alpha_threshd_edge.jpg',edge)
cv2.imwrite('10years_result.jpg',result)
# show thresh and result
cv2.imshow("bgr", bgr)
cv2.imshow("alpha", alpha)
cv2.imshow("thresh", thresh)
cv2.imshow("thresh_inv", thresh_inv)
cv2.imshow("edge", edge)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Alpha channel image:
Alpha blurred and thresholded:
Above inverted and blurred:
Edge Image:
Result:
Is this what you wanted?
Upvotes: 0
Reputation: 53164
Here is one way to do that in Python/OpenCV. Note that I reduced the size of your input.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('hjemsokt_small.png', cv2.IMREAD_UNCHANGED)
# extract bgr image
bgr = img[:,:,0:3]
# extract alpha channel
alpha = img[:,:,3]
# get largest contours
contours = cv2.findContours(alpha, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# smooth contour
peri = cv2.arcLength(big_contour, True)
big_contour = cv2.approxPolyDP(big_contour, 0.001 * peri, True)
# draw white filled contour on black background
contour_img = np.zeros_like(alpha)
cv2.drawContours(contour_img, [big_contour], 0, 255, -1)
# apply dilate to connect the white areas in the alpha channel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (40,40))
dilate = cv2.morphologyEx(contour_img, cv2.MORPH_DILATE, kernel)
# make edge outline
edge = cv2.Canny(dilate, 0, 200)
# thicken edge
edge = cv2.GaussianBlur(edge, (0,0), sigmaX=0.3, sigmaY=0.3)
# make background
result = np.full_like(bgr, (255,255,255))
# invert dilated image and blur
dilate_inv = 255 - dilate
dilate_inv = cv2.GaussianBlur(dilate_inv, (0,0), sigmaX=21, sigmaY=21)
dilate_inv = cv2.merge([dilate_inv,dilate_inv,dilate_inv])
# overlay blurred dilated area on background
result[dilate_inv>0] = dilate_inv[dilate_inv>0]
# overlay dilated white region
result[dilate==255] = (255,255,255)
# overlay bgr image
result[contour_img==255] = bgr[contour_img==255]
# overlay edge
result[edge!=0] = (96,96,96)
# save resulting images
cv2.imwrite('hjemsokt_small_alpha.jpg',alpha)
cv2.imwrite('hjemsokt_small_contour.jpg',contour_img)
cv2.imwrite('hjemsokt_small_alpha_dilated.jpg',dilate)
cv2.imwrite('hjemsokt_small_alpha_dilated_inv.jpg',dilate_inv)
cv2.imwrite('hjemsokt_small_alpha_dilated_edge.jpg',edge)
cv2.imwrite('hjemsokt_small_result.jpg',result)
# show thresh and result
cv2.imshow("bgr", bgr)
cv2.imshow("alpha", alpha)
cv2.imshow("contour_img", contour_img)
cv2.imshow("dilate", dilate)
cv2.imshow("dilate_inv", dilate_inv)
cv2.imshow("edge", edge)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Alpha channel:
Contour Image:
Smoothed Dilated contour image:
Inverted contour blurred:
Edge image:
Result:
Upvotes: 7