一个tesseract ocr box 文件查看toy,python


import os
from tkinter import *
from tkinter.filedialog import *
from  PIL import Image , ImageTk


"""
注意:*** 本程序并不保证 box 数据处理得正确,仅供参考.***
      *** 也不是JAVA那个编辑器的替代,这里不处理tiff图片 ***
      *** 没有什么新技术 ***
      *** 没有详细了解 tesseract 的种种规范 ***
#----------------------------------------------
本程序的主要目标
1,可以调整和保存 box 的坐标值。

2,呈现 一张jpg或者png图片 对应的 boxfile 。

#------------------------------------使用方法-----------------------

1 用按钮「浏览/打开」打开图片文件。
    关联的 .box文件(同名,不同后缀)会自动打开。
    若找不到相关box文件,有提示信息。

   程序把box 文件里面的字符和坐标信息读进内部字典 {boxes_data}

2 在「修改」输入框输入文字,用于修改ocr识别的字符。
  按下「替换」按钮,将会改变 {boxes_data} 对应的字符。

  真正输出一个更改过的文件,要按最下边的「保存」按钮,
  来把内部字典 {boxes_data}里面的信息写入文件。「 y_什么.box」

  注* 删除、隐藏,的box 不写入文件

3 「字」输入框是用来查找某个识别字符用的。(当然,有可能是“错误”的字符。)
   通过按下面的「⚲」按钮查找。
   查找会改变右边图片的显示,故按钮「▢」是用来恢复原来的显示。
   go 是按canvas绘图id查看。因为本app做了些预备动作...所以都是以6开始。

4 拉动滚动条观看图片“隐藏”的部分。
  也可以用鼠标中间滚轮在图片上,滚动。
  按住ctrl + 滚轮,可以调整水平方向的显示。<---->

5 esc键: 显示或者隐藏 蓝色十字架

6 ctrl+鼠标左键拖动 创建新的box

7 鼠标左键双击一个box,它将跟着鼠标走,然后到某个地方,点击,就停下

8 修改 box 坐标,可以点击滑条前进路上一点点调节,或者按着拖动它。
  下面几个按钮 [A] /A/ <A> 意味着选择调节x1,y1| 还是|x2,y2; /平移/;<缩小放大>

-----------------------------
# 如果想把frame0 搬到frame7,那么请自己动手 ……
"""
root=Tk()
#---------------------------------
East_of_left_part=600 #右边 CANVAS 的开始边界

root.wm_title("OCR调整box")
root.wm_minsize(East_of_left_part,600) #设置窗口最小时候的大小
#  总的窗口size

topwindow_width=1200
topwindow_height=700
root.geometry('%dx%d+%d+%d'%(topwindow_width,topwindow_height,200,100))
root.resizable(width=True, height=False)

#-------------------

## 基本坐标

frame_point_x=[[0,135,466,East_of_left_part],              ##  y0 :y1        第0棑 的分块(横坐标)(配 y0 )
           [0,180,400,East_of_left_part],         ##  y1 :y2        第1棑 的分块
           [0,380,East_of_left_part],             ##  y2 :y3        第2棑 的分块
           [0,East_of_left_part],                 ##  y3 :y4        第3棑 的分块
           [East_of_left_part ,topwindow_width] ,  ##  y0 :y4:       右边 图片区
        ]


frame_point_y=[0,300,385,topwindow_height-50,topwindow_height]

## frame_diagonals:各个frame的 坐标列表
frame_diagonals=[]
for i in range(4):
    match_a=[(x,frame_point_y[i])  for x in frame_point_x[i][:-1]]
    match_b=[(x,frame_point_y[i+1])for x in frame_point_x[i][1:]]
    frame_diagonals += tuple(zip(match_a,match_b))

frame_diagonals += tuple(zip([East_of_left_part,topwindow_width],[0,topwindow_height])),
#--------

def get_width_height_lefttop_of_frame(fr_No):
    p1,p2=frame_diagonals[fr_No]
    w=p2[0] - p1[0]
    h=p2[1] - p1[1]
    return w,h,p1
#-----------
frm_obj={
   }
def frm_predo(fr_No): ## 作frame 但还没显示
        frw,frh,p1=get_width_height_lefttop_of_frame(fr_No)
        obj= Frame(root,width = frw, height = frh)
        frm_obj[fr_No]=obj  ## 记录在 frm_obj 字典

for f in range(10):
    frm_predo(f)
#-----
def place_frm(fr_No): ## 把tk"组件"摆放出来
    obj=frm_obj[fr_No]
    px,py=get_width_height_lefttop_of_frame(fr_No)[2] # frw ...0,   frh ...1 ,  p1 ...2
    obj.place(x=px,y=py)

#---------------------------------------------公共数据部分------------------------------------------------------------------
# boxes_data 一个记录字符box坐标的字典。在打开box文件后填写内容,现在提前说一下。
#----------------------

a_z=[0,0]    # 绘图id [第一个:最后一个] (box序号)注:第一个并不一定是1(1可能是指底图)
boxes_data={
   }
using   = 1     # box 状态。
waiting = 0      # box 状态。“删除”后的状态。
boxes_been_kiled=[] # 记录被删除的box id,垃圾回收
page_num=0 # 图片内部编号
imge_w,imge_h=0,0 # 图片尺寸。「打开图片时,重新赋值。」
#---------------------------------------------------------------------------------------

#-----------------------------------下面是各个框架的填写--------------------------------
#// frame_0 /// frame_0
"""\
1, 显示选择的box识别的字符。
2, 提供修改字符的输入框。
------------------------------------------------------------------"""
fobj0=frm_obj[0]
w0,h0,pf01=get_width_height_lefttop_of_frame(0)

#-----------变量----
frame0_char_from_data= StringVar()
frame0_char_to_data= StringVar()
frame0_box_id =  StringVar()

def frame0_box_id_get():
    it = 0 if frame0_box_id.get()=="" else int(frame0_box_id.get())
    return it
def frame0_box_id_set(n):
    frame0_box_id.set("" if n==0 else str(n))

#-------------
data_char_changed_back =[] # 备份 (修改字符)

def frame0_correct4char( ):
    char_back= frame0_char_from_data.get()
    change= frame0_char_to_data.get().strip()

    if change=="":return  #没有输入 (要修改成的字符),则不做下面的工作.

    it = frame0_box_id_get()

    if it != -1 :#   # 修改字符 条件
        '''step 1'''
        frame0_char_from_data.set(change) #修改上面的ocr显示
        frame0_char_to_data.set("")       #输入框 清空
        '''step 2'''

        boxes_data[it][0]=change #修改字典里的data
        frame6_show_MSG .set('字典改写字符 box: '+str(it)+" "+change) #显示消息
        data_char_changed_back.append((it,char_back)) # 备份

#显示 box 区域 对应的 OCR 字符
def  frame0_pass_chr_to_chrTEXT():
     frame0_char_to_data.set(frame0_char_from_data.get())

frame0_ocr_label=Label(fobj0,text="ocr ") ;     frame0_ocr_label.place(x=10,y=30)
frame0_box_id_label= Label(fobj0,textvariable= frame0_box_id,width=6,) ;     frame0_box_id_label.place(x=30,y=30)
frame0_char_label=Label(fobj0,font=("Courtier",22), textvariable=frame0_char_from_data,bg="white",fg="green",width=5) ;frame0_char_label.place(x=10,y=50)
frame0_trButton=Button(fobj0,
       text = '↓↓',
       command = frame0_pass_chr_to_chrTEXT,
       width=2
       );frame0_trButton.place(x=40,y=94)

#输入字符的”Entry"组件。(修改 box 圈住的字符)
def iframe0_correct4char(e):
    frame0_correct4char()
frame0_correct_label=Label(fobj0,text="修改");frame0_correct_label.place(x=10,y=130)
frame0_chrTEXT=Entry(fobj0,font=("Courtier",26),textvariable=frame0_char_to_data,width=5); frame0_chrTEXT.place(x=10,y=150)
frame0_chrTEXT.bind("<Return>",iframe0_correct4char)
frame0_chrTEXT.bind("<KP_Enter>",iframe0_correct4char)

#----------
def change_char():
        #frame6_show_MSG.set("你点击了 replace 的按钮")
        frame0_correct4char()

def undo_boxfile():
        #frame6_show_MSG.set("你点击了 undo 的按钮") #
        if data_char_changed_back !=[]:
            it,ch= data_char_changed_back.pop()
            boxes_data[it][0]=ch
            frame6_show_MSG.set('字典改写字符 box: '+str(it)+" "+ch)

frame0_udButton=Button(fobj0,
       text = 'undo',
       command = undo_boxfile
       );frame0_udButton.place(x=5,y=202)

frame0_rpButton=Button(fobj0,
       text = '替换',
       command = change_char,
       );frame0_rpButton.place(x=60,y=202)


#-----------------------
def frame0_change_ocr_show(it):

    ch=boxes_data[it][0]
    frame0_char_from_data.set(ch)
    frame0_box_id_set(it)



#// frame_1 
"""\
调整box 时的显示窗口。
滑条合二为一: 当按下切换按钮时,分别用来调节 X1<>X2,Y1<>Y2.
------------------------------------------------------------------------------------------------"""

fobj1=frm_obj[1]
w1,h1,pf1_1=get_width_height_lefttop_of_frame(1)

frm1_scale_12=IntVar() # 或者1 或者2 -- 分别代表着x1y1,x2y2。
frm1_scale_12.set(1)

#  放大/调整 box 大小的地方---------
frame1_adjust_box=Canvas(fobj1,bg = '#DEEE84',width = w1, height =h1*0.7+8)
frame1_adjust_box.place(x=0,y=h1*0.05)

# x 控制条-----------
"""控制条直接改变的是fram9里的box,并不是frame1的显示"""
def frame1_x1x2scale(e):
    """获取当前 box 坐标"""
    e=int(e)
    it=frame0_box_id_get()

    if  boxes_data.get(it,None)==None:return
    else:
        x1,y1,x2,y2= boxes_data[it][1]
    """调整坐标"""
    if frm1_scale_12.get()==1: # left & top
        if x1+e < x2 :
            x1+= e
            frame4_Xwest.set(x1)

    elif  frm1_scale_12.get()==2:
        if x2 + e >x1:
            x2 += e
            frame4_Xeast.set(x2)
    elif  frm1_scale_12.get()==3: #平移
        x1 += e
        x2 += e
        frame4_Xwest.set(x1)
        frame4_Xeast.set(x2)
    elif  frm1_scale_12.get()==4: #缩小,但是缩小到宽度为零?另外负数缩小=扩大?
        if x1 + 2*e < x2 :
            x1 += e
            x2 -= e
            frame4_Xwest.set(x1)
            frame4_Xeast.set(x2)

    elif  frm1_scale_12.get()==0:
        if x1 - 2*e < x2 :
            x1 -= e
            x2 += e
            frame4_Xwest.set(x1)
            frame4_Xeast.set(x2)

    if x2>=x1:
        frame4_Xwidth.set(x2 -x1)
    """改变边框"""
    box=[x1,y1,x2,y2]
    frame9_change_char_border(it,box)
#------------

frame1_BOXleftScale=Scale(fobj1, # 左边
      from_ = -150,         #设置最小值
      to = 150,             #设置最大值
      resolution =1,       #设置步距值
      orient = HORIZONTAL,   #设置水平方向
      width=10,
      #sliderrelief=FLAT,
      sliderlength=20, #默认是30
      length=320,
     font=("Arial",8),
     #relief=FLAT,
      #label="x1",
       command=frame1_x1x2scale
      )
frame1_BOXleftScale.place(x=0,y=frame_point_y[1]-50)

def when_mouse_leave_scale(e):
    frame1_BOXleftScale.set(0)
    frame2_BOXtopScale.set(0)
    if frame0_box_id_get() !=0:
        frame2_alter_box_coordinate()

frame1_BOXleftScale.bind("<Leave>",when_mouse_leave_scale)

def refresh_ocr_show(it): #更新显示
    if it not in boxes_data: return # 可能在删除全部的box后,显示有些问题
    frame0_change_ocr_show(it)
    put_img2_canvas(it)
    put_coordinates_from_dict_to_entrys(it)
#// frame_2 
"""\
这一块用于调节某字符的盒子位置竖直偏移量,和高度。
----------------------------------------------------------------------"""
fobj2=frm_obj[2]
w2,h2,pf2_1=get_width_height_lefttop_of_frame(2)
onestep=1
#--------

#--------滑条

def frame2_y1y2scale(e):
    """获取当前 box 坐标"""
    e=int(e)
    it=frame0_box_id_get()
    if  boxes_data.get(it,None)==None:return
    else:
        x1,y1,x2,y2= boxes_data[it][1]
    """调整坐标"""
    if frm1_scale_12.get()==1:
        if y1+ e < y2 :
            y1+= e
            frame2_Xnorth.set(y1)

    elif  frm1_scale_12.get()==2:
        if y2 + e >y1:
            y2 += e
            frame2_Xsouth.set(y2)
    elif  frm1_scale_12.get()==3: #平移
        y1 += e
        y2 += e
        frame2_Xnorth.set(y1)
        frame2_Xsouth.set(y2)
    elif  frm1_scale_12.get()==4: #缩小,但是缩小到宽度为零?另外负数缩小=扩大?
        if y1 + 2*e < y2 :
            y1 += e
            y2 -= e
            frame2_Xnorth.set(y1)
            frame2_Xsouth.set(y2)

    elif  frm1_scale_12.get()==0:
        if y1 - 2*e < y2 :
            y1 -= e
            y2 += e
            frame2_Xnorth.set(y1)
            frame2_Xsouth.set(y2)

    if y2>=y1:
        frame2_Xheight.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值