Python + opencv 實現圖片文字的分割


實現步驟:

1、通過水平投影對圖形進行水平分割,獲取每一行的圖像;

2、通過垂直投影對分割的每一行圖像進行垂直分割,最終確定每一個字符的坐標位置,分割出每一個字符;

   先簡單介紹一下投影法:分別在水平和垂直方向對預處理(二值化)的圖像某一種像素進行統計,對於二值化圖像非黑即白,我們通過對其中的白點或者黑點進行統計,根據統計結果就可以判斷出每一行的上下邊界以及每一列的左右邊界,從而實現分割的目的。

下面通過Python+opencv來實現該功能

首先來實現水平投影:

import cv2
import numpy as np

'''水平投影'''
def getHProjection(image):
    hProjection = np.zeros(image.shape,np.uint8)
    #圖像高與寬
    (h,w)=image.shape 
    #長度與圖像高度一致的數組
    h_ = [0]*h
    #循環統計每一行白色像素的個數
    for y in range(h):
        for x in range(w):
            if image[y,x] == 255:
                h_[y]+=1
    #繪制水平投影圖像
    for y in range(h):
        for x in range(h_[y]):
            hProjection[y,x] = 255
    cv2.imshow('hProjection2',hProjection)

    return h_

if __name__ == "__main__":
    #讀入原始圖像
    origineImage = cv2.imread('test.jpg')
    # 圖像灰度化    
    #image = cv2.imread('test.jpg',0)
    image = cv2.cvtColor(origineImage,cv2.COLOR_BGR2GRAY)
    cv2.imshow('gray',image)
    # 將圖片二值化
    retval, img = cv2.threshold(image,127,255,cv2.THRESH_BINARY_INV)
    cv2.imshow('binary',img)
    #水平投影
    H = getHProjection(img)

 

通過上面的水平投影,根據其白色小山峰的起始位置就可以界定出每一行的起始位置,從而把每一行分割出來。

獲得每一行圖像之后,可以對其進行垂直投影

def getVProjection(image):
    vProjection = np.zeros(image.shape,np.uint8);
    #圖像高與寬
    (h,w) = image.shape
    #長度與圖像寬度一致的數組
    w_ = [0]*w
    #循環統計每一列白色像素的個數
    for x in range(w):
        for y in range(h):
            if image[y,x] == 255:
                w_[x]+=1
    #繪制垂直平投影圖像
    for x in range(w):
        for y in range(h-w_[x],h):
            vProjection[y,x] = 255
    cv2.imshow('vProjection',vProjection)
    return w_

 

通過垂直投影可以獲得每一個字符左右的起始位置,這樣也就可以獲得到每一個字符的具體坐標位置,即一個矩形框的位置。

下面是實現的全部代碼:

import cv2
import numpy as np

'''水平投影'''
def getHProjection(image):
    hProjection = np.zeros(image.shape,np.uint8)
    #圖像高與寬
    (h,w)=image.shape 
    #長度與圖像高度一致的數組
    h_ = [0]*h
    #循環統計每一行白色像素的個數
    for y in range(h):
        for x in range(w):
            if image[y,x] == 255:
                h_[y]+=1
    #繪制水平投影圖像
    for y in range(h):
        for x in range(h_[y]):
            hProjection[y,x] = 255
    cv2.imshow('hProjection2',hProjection)

    return h_

def getVProjection(image):
    vProjection = np.zeros(image.shape,np.uint8);
    #圖像高與寬
    (h,w) = image.shape
    #長度與圖像寬度一致的數組
    w_ = [0]*w
    #循環統計每一列白色像素的個數
    for x in range(w):
        for y in range(h):
            if image[y,x] == 255:
                w_[x]+=1
    #繪制垂直平投影圖像
    for x in range(w):
        for y in range(h-w_[x],h):
            vProjection[y,x] = 255
    #cv2.imshow('vProjection',vProjection)
    return w_

if __name__ == "__main__":
    #讀入原始圖像
    origineImage = cv2.imread('test.jpg')
    # 圖像灰度化    
    #image = cv2.imread('test.jpg',0)
    image = cv2.cvtColor(origineImage,cv2.COLOR_BGR2GRAY)
    cv2.imshow('gray',image)
    # 將圖片二值化
    retval, img = cv2.threshold(image,127,255,cv2.THRESH_BINARY_INV)
    cv2.imshow('binary',img)
    #圖像高與寬
    (h,w)=img.shape 
    Position = []
    #水平投影
    H = getHProjection(img)

    start = 0
    H_Start = []
    H_End = []
    #根據水平投影獲取垂直分割位置
    for i in range(len(H)):
        if H[i] > 0 and start ==0:
            H_Start.append(i)
            start = 1
        if H[i] <= 0 and start == 1:
            H_End.append(i)
            start = 0
    #分割行,分割之后再進行列分割並保存分割位置
    for i in range(len(H_Start)):
        #獲取行圖像
        cropImg = img[H_Start[i]:H_End[i], 0:w]
        #cv2.imshow('cropImg',cropImg)
        #對行圖像進行垂直投影
        W = getVProjection(cropImg)
        Wstart = 0
        Wend = 0
        W_Start = 0
        W_End = 0
        for j in range(len(W)):
            if W[j] > 0 and Wstart ==0:
                W_Start =j
                Wstart = 1
                Wend=0
            if W[j] <= 0 and Wstart == 1:
                W_End =j
                Wstart = 0
                Wend=1
            if Wend == 1:
                Position.append([W_Start,H_Start[i],W_End,H_End[i]])
                Wend =0
    #根據確定的位置分割字符
    for m in range(len(Position)):
        cv2.rectangle(origineImage, (Position[m][0],Position[m][1]), (Position[m][2],Position[m][3]), (0 ,229 ,238), 1)
    cv2.imshow('image',origineImage)
    cv2.waitKey(0)

 

  從分割的結果上看,基本上實現了圖片中文字的分割。但由於中文結構復雜性,對於一些文字的分割並不理想,比如“葉”、“桃”等字會出現過度分割現象;對於有粘連的兩個字會出現分割不夠的現象,比如上圖中的“念想”。不過可以從圖像預處理(腐蝕),邊界判斷閾值的調整等方面進行優化。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM