SoFunction
Updated on 2024-11-13

python captcha recognition tutorial of the use of the drip algorithm to segment the picture

Overview of the Drip Algorithm

Drip algorithm is an algorithm used to split handwritten sticky characters, with the previous linear division of different , it simulates the rolling of the water droplets, through the rolling path of the water droplets to split the characters, can solve the linear cutting caused by the excessive division of the problem.

introductory

Previously mentioned for the sticky characters can be used to solve the splitting of the drip algorithm, but the IQ is anxious I really can not comprehend the essence of this algorithm, fortunately there are small partners have been realized related to thecoding

I made some minor changes to the code above while upgrading to python3.

Or take this picture as an example:

In previous we have known that this simple adhesion can be segmented by controlling the threshold, here we use the dropping algorithm.

first usingPreviously in the articleThe introduced vertical projection or connected domain is first processed with one cut to get the result as follows:

The final adhesion case is dealt with using the drip algorithm:

from itertools import groupby

def binarizing(img,threshold):
 """Pass in image object for grayscale, binary processing"""
 img = ("L") # To grayscale
 pixdata = ()
 w, h = 
 # Iterate over all pixels, those greater than the threshold are black
 for y in range(h):
  for x in range(w):
   if pixdata[x, y] < threshold:
    pixdata[x, y] = 0
   else:
    pixdata[x, y] = 255
 return img

def vertical(img):
 """Pass in binarized image for vertical projection."""
 pixdata = ()
 w,h = 
 result = []
 for x in range(w):
  black = 0
  for y in range(h):
   if pixdata[x,y] == 0:
    black += 1
  (black)
 return result

def get_start_x(hist_width):
 """Determine the starting point based on the vertical projection of the image.
  hist_width middle value 4 values before and after, and then the minimum value within this range.
 """
 mid = len(hist_width) // 2 # Note that py3 division is different from py2 #
 temp = hist_width[mid-4:mid+5]
 return mid - 4 + (min(temp))

def get_nearby_pix_value(img_pix,x,y,j):
 """Getting 5 points of pixel data in close proximity."""
 if j == 1:
  return 0 if img_pix[x-1,y+1] == 0 else 1
 elif j ==2:
  return 0 if img_pix[x,y+1] == 0 else 1
 elif j ==3:
  return 0 if img_pix[x+1,y+1] == 0 else 1
 elif j ==4:
  return 0 if img_pix[x+1,y] == 0 else 1
 elif j ==5:
  return 0 if img_pix[x-1,y] == 0 else 1
 else:
  raise Exception("get_nearby_pix_value error")


def get_end_route(img,start_x,height):
 """Getting the drip path"""
 left_limit = 0
 right_limit = [0] - 1
 end_route = []
 cur_p = (start_x,0)
 last_p = cur_p
 end_route.append(cur_p)

 while cur_p[1] < (height-1):
  sum_n = 0
  max_w = 0
  next_x = cur_p[0]
  next_y = cur_p[1]
  pix_img = ()
  for i in range(1,6):
   cur_w = get_nearby_pix_value(pix_img,cur_p[0],cur_p[1],i) * (6-i)
   sum_n += cur_w
   if max_w < cur_w:
    max_w = cur_w
  if sum_n == 0:
   # If it's all black then look at the inertia
   max_w = 4
  if sum_n == 15:
   max_w = 6

  if max_w == 1:
   next_x = cur_p[0] - 1
   next_y = cur_p[1]
  elif max_w == 2:
   next_x = cur_p[0] + 1
   next_y = cur_p[1]
  elif max_w == 3:
   next_x = cur_p[0] + 1
   next_y = cur_p[1] + 1
  elif max_w == 5:
   next_x = cur_p[0] - 1
   next_y = cur_p[1] + 1
  elif max_w == 6:
   next_x = cur_p[0]
   next_y = cur_p[1] + 1
  elif max_w == 4:
   if next_x > cur_p[0]:
    # To the right
    next_x = cur_p[0] + 1
    next_y = cur_p[1] + 1
   if next_x < cur_p[0]:
    next_x = cur_p[0]
    next_y = cur_p[1] + 1
   if sum_n == 0:
    next_x = cur_p[0]
    next_y = cur_p[1] + 1
  else:
   raise Exception("get end route error")

  if last_p[0] == next_x and last_p[1] == next_y:
   if next_x < cur_p[0]:
    max_w = 5
    next_x = cur_p[0] + 1
    next_y = cur_p[1] + 1
   else:
    max_w = 3
    next_x = cur_p[0] - 1
    next_y = cur_p[1] + 1
  last_p = cur_p

  if next_x > right_limit:
   next_x = right_limit
   next_y = cur_p[1] + 1
  if next_x < left_limit:
   next_x = left_limit
   next_y = cur_p[1] + 1
  cur_p = (next_x,next_y)
  end_route.append(cur_p)
 return end_route

def get_split_seq(projection_x):
 split_seq = []
 start_x = 0
 length = 0
 for pos_x, val in enumerate(projection_x):
  if val == 0 and length == 0:
   continue
  elif val == 0 and length != 0:
   split_seq.append([start_x, length])
   length = 0
  elif val == 1:
   if length == 0:
    start_x = pos_x
   length += 1
  else:
   raise Exception('generating split sequence occurs error')
 # If length is not 0 at the end of the loop, there is still a part to append.
 if length != 0:
  split_seq.append([start_x, length])
 return split_seq


def do_split(source_image, starts, filter_ends):
 """
 Cutting in practice
 : param starts: tuple of list
 : param ends: the end of each line
 """
 left = starts[0][0]
 top = starts[0][1]
 right = filter_ends[0][0]
 bottom = filter_ends[0][1]
 pixdata = source_image.load()
 for i in range(len(starts)):
  left = min(starts[i][0], left)
  top = min(starts[i][1], top)
  right = max(filter_ends[i][0], right)
  bottom = max(filter_ends[i][1], bottom)
 width = right - left + 1
 height = bottom - top + 1
 image = ('RGB', (width, height), (255,255,255))
 for i in range(height):
  start = starts[i]
  end = filter_ends[i]
  for x in range(start[0], end[0]+1):
   if pixdata[x,start[1]] == 0:
    ((x - left, start[1] - top), (0,0,0))
 return image

def drop_fall(img):
 """Drip splitting."""
 width,height = 
 # 1 Binarization
 b_img = binarizing(img,200)
 # 2 Vertical projection
 hist_width = vertical(b_img)
 # 3 Getting Started
 start_x = get_start_x(hist_width)

 # 4 Start the drip algorithm
 start_route = []
 for y in range(height):
  start_route.append((0,y))

 end_route = get_end_route(img,start_x,height)
 filter_end_route = [max(list(k)) for _,k in groupby(end_route,lambda x:x[1])] # Note the groupby here
 img1 = do_split(img,start_route,filter_end_route)
 ('')

 start_route = list(map(lambda x : (x[0]+1,x[1]),filter_end_route)) # python3 map does not return list need to convert yourself
 end_route = []
 for y in range(height):
  end_route.append((width-1,y))
 img2 = do_split(img,start_route,end_route)
 ('')

if __name__ == '__main__':
 p = ("")
 drop_fall(p)

Executing it will give you the sliced 2 photos:


From this picture, although the cut is successful, but the effect is more general. In addition, the current code can only cut the case of 2 characters sticking together, the realization of the essence of the drip algorithm partners can try to change to multiple characters sticking together.

summarize

Above is the entire content of this article, I hope that the content of this article on your learning or work has a certain reference learning value, if there are questions you can leave a message to exchange, thank you for my support.