[原创]-python实用小工具之camera tuning小助手

  最近一直在忙,好久没有上博客园更新文章。趁着有空,将近期用python实现的一个小工具发布出来。这个是本人在实际的工作当中,为了提高效率而开发的一个小工具。正所谓"麻雀虽小,五脏俱全”,虽然是一个简单的小工具,也包含了很多的知识点在里面,也当是这段时间接触python的一次小结吧。与此同时,后期还会不断的完善,该版本只是一个雏形,仅仅实现了最基本的功能,还有很多的地方不是很完善,所以后期会不断的更新。


需求:

  本人从事camera影像调试的工作,在高通平台下tuning手机摄像头模组。在实际的工作当中,发现有很多拍摄RAW图的时间比较繁琐,而且很多是重复的操作,特别是客观调试的时候,场景基本上都是固定了,但是我们每次去拍照的时候,需要在一个场景下拍图,然后把RAW图导出来,同时更改文件名。很多老练的工程师,都已经习惯了,一个一个的拍,然后改名,放到不同的文件夹下面,中间又需要不断地敲命令导出raw图。可想而知,如果项目的周期很赶,那么使用手动的方式,效率上会浪费比较多的时间,而且容易乱。本人又比较懒,同时又发现了这其中有很多操作是重复的,所以就打算自己写一个工具,来实现大部分的工作,这样就可以节省了比较多的时间,用于真正的分析重要问题上面。

需求分析:

  既然我们已经知道了要做什么事情,就需要不断地去需求摸清楚,然后选择合适的工具去实现。由于实际的工作又比较简单,用脚本的方式是最容易思实现的,并且不需要编译啥的,即使换一台机器,在相同的操作系统下面仍然能用,省去了很多的麻烦。最开始是使用脚本的方式,比较简单,代码很少,如下:

@echo off
rem 在运行该脚本前,请先打开手机的骁龙相机,并设置相应的RAW图开关
rem ============================================================== 

rem 下面两个路径是手机中Raw图的存放位置,和pull出来的raw存放路径,请检查
set PHONE_JPG_PATH=sdcard/DCIM/Camera/
set PHONE_RAW_PATH=sdcard/DCIM/Camera/raw/
set PULL_RAW_PATH=./raw/
rem echo PHONE_RAW_PATH=%PHONE_RAW_PATH%
rem echo PULL_RAW_PATH=%PULL_RAW_PATH%
rem =============================================================== 
adb wait-for-device
adb root
adb wait-for-device
adb remount

rem 打开骁龙相机
rem adb shell am start -a android.media.action.STILL_IMAGE_CAMERA
rem num27表示的是执行拍照动作
adb shell input keyevent 27
rem ================================================================
rem 修改颜色 color 03
echo 请稍等
ping -n 6 127.1 >nul
echo 开始导出RAW文件
adb pull sdcard/DCIM/Camera/raw/ ./raw/
adb shell rm /sdcard/DCIM/Camera/raw/*.raw  
adb pull %PHONE_RAW_PATH% %PULL_RAW_PATH%
rem ren %PULL_RAW_PATH%/*.raw %PULL_RAW_PATH%/%1_Lux.raw

echo 删除phone中的RAW图成功! 
View Code

   但是实际使用的效果,不太好,仍然需要输入很多的命令,并且切换多个目录,一不小心就出错了,浪费比较多的时间。所以就打算进一步的改善。刚好了解到了python,学了一段时间,然后渐渐改良了原来的版本。 

目前实现的效果:

  

  

 代码如下:

  1 # -*- coding: utf-8 -*-
  2 # ---------------------------------------------------------------------------
  3 # tuning capure pic tools
  4 # This is a free software .
  5 #
  6 # Author: Qibaowei
  7 # Bug report:  
  8 # ---------------------------------------------------------------------------
  9 #
 10 # Function:
 11 #   capure the image to local path
 12 # Version:
 13 #   V1.0 (python 3.7)
 14 # Usage:
 15 #   v1.pyw  
 16 # Example:
 17 #   v1.pyw
 18 
 19 
 20 try:
 21     import tkinter as tk
 22     import tkinter.messagebox
 23     from tkinter import scrolledtext 
 24     from tkinter import ttk
 25 except:
 26     print ('Following module is needed:')
 27     print ('- Tkinter: check the python -v and ensure the version is py3.x')
 28     sys.exit()
 29 
 30 # cmd所依赖的系统库
 31 import os
 32 import time
 33 import re
 34 
 35 # 当配置栏为空时,注意弹出窗口,并且提示。
 36 # 同时配置栏更改时也需要弹出提示窗口
 37 
 38 # 配置路径
 39 RawPath = "sdcard/DCIM/Camera/raw/"
 40 JpgPath = "sdcard/DCIM/Camera/"
 41 SavePicPath = "./raw/"
 42 
 43 # 下拉列表中的值
 44 gScenceValue=['BLC','Rollof','MCC','18%Gray','ISO12233','GrayStep','Flat Field' ]
 45 gLightValue =['A','H','TL84','CWF','U30','D50','D65','D75','LED','Flash','outdoor']
 46 gLuxValue   =[10,20,50,100,200,400,500,1000,'Normal','Low']
 47 gFormatValue=['raw','jpg']
 48 
 49 SavePicName = ' '
 50 ChosenType = 0
 51 ###########################################################################################
 52 class Setting:
 53     def __init__(self,root):
 54         global RawPath
 55         global JpgPath
 56         global SavePicPath
 57         
 58         self.lf_setting = tk.LabelFrame(root, width=240, height=320,text='配置',fg='Tomato')
 59         self.lf_setting.grid(columnspan=3,row=0, column=0, sticky='N'+'S'+'W'+'E',padx=10, pady=6)
 60 
 61         
 62         local = tk.StringVar()
 63         Raw   = tk.StringVar()
 64         Jpg   = tk.StringVar()
 65 
 66         local.set(SavePicPath)
 67         Raw.set(RawPath)
 68         Jpg.set(JpgPath)
 69         
 70         tk.Label(self.lf_setting,text="手机RAW文件路径").grid(row=0,column=0,sticky='E')
 71         tk.Label(self.lf_setting,text="手机JPG文件路径").grid(row=1,column=0,sticky='E')#第二行
 72         tk.Label(self.lf_setting,text="本地保存路径").grid(row=2,column=0,sticky='E')
 73         self.RawPath  = tk.Entry(self.lf_setting, width=60,bg='PaleGreen',fg='red',textvariable =Raw,state = 'disabled').grid(row=0,column=1)
 74         self.JpgPath  = tk.Entry(self.lf_setting, width=60,bg='PaleGreen',fg='red',textvariable =Jpg,state = 'disabled').grid(row=1,column=1)
 75         self.SavePath = tk.Entry(self.lf_setting, width=60,bg='PaleGreen',fg='red',textvariable =local,state = 'disabled').grid(row=2,column=1)
 76 
 77         
 78         
 79     def GetPhoneRawPath(self):
 80         print(self.RawPath.get())
 81 
 82     def GetPhoneJpgPath(self):
 83         print(self.JpgPath.get())
 84 
 85     def GetSavePicPath(self):
 86         print(self.SavePath.get())
 87         
 88     def work(self):
 89         print('setting tab')
 90 
 91 #######################################################################################
 92 class Scene:
 93     def __init__(self,root):
 94         self.lf_res = tk.LabelFrame(root, width=40, height=20, text='拍摄场景',fg='Maroon')  
 95         self.lf_res.grid(row=1, column=0, sticky='W'+'N'+'E',padx=10, pady=5)
 96         # 场景
 97         self.LbScene = tk.Label(self.lf_res,text="场景").grid(row=0,column=0,sticky='E',padx=10, pady=2)
 98         StSceneSelect = tk.StringVar()
 99         self.CChosen = ttk.Combobox(self.lf_res, width=12, textvariable=StSceneSelect, state='readonly')
100         self.CChosen['values'] = gScenceValue
101         #self.CChosen['values'] = ('BLC','Rollof','MCC','18%Gray','ISO12233','GrayStep','Flat Field')     # 设置下拉列表的值
102         self.CChosen.grid(row=0,column=1)      # 设置其在界面中出现的位置  column代表列   row 代表行
103         self.CChosen.current(2)    # 设置下拉列表默认显示的值,0为 numberChosen['values'] 的下标值        
104         self.CChosen.bind("<<ComboboxSelected>>", self.SceneSelect)
105         
106         # 光源
107         self.LbLight = tk.Label(self.lf_res,text="光源").grid(row=1,column=0,sticky='E',padx=10, pady=2)
108         StLightSelect = tk.StringVar()
109         self.LightChosen = ttk.Combobox(self.lf_res, width=12,textvariable=StLightSelect, state='readonly')
110         self.LightChosen['values'] = gLightValue
111         #self.LightChosen['values'] = ('A','H','TL84','CWF','U30','D50','D65','D75','LED','Flash','outdoor')    
112         self.LightChosen.grid(row=1,column=1)      
113         self.LightChosen.current(2)    
114         self.LightChosen.bind("<<ComboboxSelected>>", self.SceneSelect)
115         
116         # 照度
117         StLux = tk.StringVar()
118         self.LbLux = tk.Label(self.lf_res,text="照度").grid(row=2,column=0,sticky='E',padx=10, pady=2)
119         self.LuxChosen = ttk.Combobox(self.lf_res, width=12, textvariable=StLux, state='readonly')
120         self.LuxChosen['values'] = gLuxValue
121         #self.LuxChosen['values'] = (10,20,50,100,200,400,500,1000,'Normal','Low') 
122         self.LuxChosen.grid(row=2,column=1)     
123         self.LuxChosen.current(0)    
124         self.LuxChosen.bind("<<ComboboxSelected>>", self.SceneSelect)
125         
126         # 格式
127         StFormat = tk.StringVar()
128         self.LbFormat = tk.Label(self.lf_res,text="格式").grid(row=3,column=0,sticky='E',padx=10, pady=2)
129         self.FormatChosen = ttk.Combobox(self.lf_res, width=12, textvariable=StFormat, state='readonly')
130         self.FormatChosen['values'] = gFormatValue
131         #self.FormatChosen['values'] = ('raw','jpg')
132         self.FormatChosen.grid(row=3,column=1)      
133         self.FormatChosen.current(0)    
134         self.FormatChosen.bind("<<ComboboxSelected>>", self.SceneSelect)
135 
136     def SceneSelect(self,*args):
137         global SavePicName
138         global ChosenType
139         SavePicName = (self.CChosen.get()+'_'+self.LightChosen.get()+'_'+self.LuxChosen.get()+'.'+self.FormatChosen.get())
140         print (SavePicName)
141         if self.FormatChosen.get().find("raw") != -1:
142             ChosenType = 0
143         else:
144             ChosenType = 1 
145         
146     def work(self):
147         print('Scene tab')
148 
149 #########################################################################################
150 class Control:
151     def __init__(self,root):
152         self.lf_control = tk.LabelFrame(root, width=40, height=20, text='控制',fg='Orange')  
153         self.lf_control.grid(row=1, column=1, sticky='W'+'N',padx=10, pady=5)
154 
155         self.bt_openCamera = tk.Button(self.lf_control,text='打开相机',width=10,height=2 ,command=self.OpoenCamera )
156         self.bt_openCamera.grid(row=0,column=0,padx=10,pady=20)
157         
158         self.bt_CloseCamera = tk.Button(self.lf_control,text='关闭相机',width=10,height=2,command=self.CloseCamera  )
159         self.bt_CloseCamera.grid(row=1,column=0,padx=10,pady=16)
160         
161         self.bt_Capure = tk.Button(self.lf_control,text='拍照',width=10,height=2 ,command=self.CapurePicture )
162         self.bt_Capure.grid(row=0,column=1,padx=10, pady=16)
163 
164         self.bt_ClearCamera = tk.Button(self.lf_control,text='清空图片',width=10,height=2 ,command=self.ClearPicture )
165         self.bt_ClearCamera.grid(row=1,column=1,padx=5, pady=8)        
166         self.lf_message = tk.LabelFrame(root, width=100, height=50, text='实时信息',fg='DarkGreen')
167         self.lf_message.grid(columnspan=3,row=2, column=0, sticky='W'+'E'+'N'+'S',padx=10, pady=5)
168     
169         self.yScrollbar = tk.Scrollbar(self.lf_message)
170         self.yScrollbar.pack(side = 'right', fill = 'y')
171         self.xScrollbar = tk.Scrollbar(self.lf_message, orient = 'horizontal')# HORIZONTAL 设置水平方向的滚动条,默认是竖直
172         self.xScrollbar.pack(side = 'bottom', fill = 'x') 
173         # 创建文本框,wrap 设置不自动换行
174         self.message_out = tk.Text(self.lf_message, width = 100,
175                                    bg='Black',fg='DarkViolet',
176                                    yscrollcommand = self.yScrollbar.set, xscrollcommand = self.xScrollbar.set, wrap = 'none')
177         self.message_out.pack(anchor='center')
178         
179     def OpoenCamera(self):
180         print ('open camera
')
181         global SavePicName
182         os.popen("adb remount").read()+'
'
183         StOpenCamera = os.popen("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA").read()+'
'
184         self.message_out.insert(tkinter.END, StOpenCamera)  # INSERT表示在光标位置插入
185         self.message_out.see(tkinter.END)
186         self.message_out.update()
187         print ('rename '+(SavePicName))
188     
189     def CloseCamera(self):
190         print ('close camera
')
191         StOpenCamera = os.popen("adb shell input keyevent 4").read()+'
'
192         self.message_out.insert(tkinter.END, StOpenCamera)
193         self.message_out.see(tkinter.END)
194         self.message_out.update()
195         
196     def CapurePicture(self):
197         print ('Capure 
')
198         global RawPath
199         global JpgPath
200         global SavePicPath
201         global SavePicName
202         global ChosenType        
203         if ( ChosenType == 0):
204             StOpenCamera = os.popen("adb shell input keyevent 27").read()+'
'+os.popen("ping -n 6 127.1 >nul").read()+'
'+os.popen("adb pull "+RawPath+" "+SavePicPath).read()+'
'
205             print("Choosen RAW
")
206         else:
207             StOpenCamera = os.popen("adb shell input keyevent 27").read()+'
'+os.popen("ping -n 6 127.1 >nul").read()+'
'+os.popen("adb pull "+JpgPath+" "+SavePicPath).read()+'
'
208             print("Choosen JPG
")
209         self.message_out.insert(tkinter.END, StOpenCamera)
210         self.message_out.see(tkinter.END)
211         self.message_out.update()
212         print ("adb pull "+RawPath+" "+SavePicPath)
213         for item in os.listdir(SavePicPath):
214             if (re.match(r"^IMG_d+", item)):
215                 print (item)
216                 #newname = re.sub(r"(d+)", "", item)
217                 try:
218                     os.renames(SavePicPath+item, SavePicPath+SavePicName)
219                 except OSError:
220                     pass
221                 print ("-->" + SavePicName)
222         if ( ChosenType == 0):
223             print (os.popen("adb shell rm "+RawPath+'*.raw')+'
')
224         else:
225             print (os.popen("adb shell rm "+JpgPath+'*.jpg')+'
')
226         
227     def ClearPicture(self):
228         print ('Clear raw in phone 
')
229         g_cmd_out = os.popen("adb remount").read()+'
'
230         self.message_out.delete('1.0','end')
231         
232     def work(self):
233         print('setting tab')
234 
235 ########################################################################################
236 class Calculate:
237     def __init__(self,root):
238         self.lf_calculate = tk.LabelFrame(root, width=40, height=100, text='计算')  
239         self.lf_calculate.grid(row=1, column=2, sticky='W'+'N'+'S', pady=5)
240         
241     def work(self):
242         print('Calculate tab')
243 
244 #######################################################################################
245 class Message:
246     def __init__(self,root):
247         self.lf_message = tk.LabelFrame(root, width=100, height=50, text='实时信息',fg='DarkGreen')  
248         self.lf_message.grid(columnspan=3,row=2, column=0, sticky='W'+'E'+'N'+'S',padx=10, pady=5)
249 
250         self.yScrollbar = tk.Scrollbar(self.lf_message)
251         self.yScrollbar.pack(side = 'right', fill = 'y')
252         self.xScrollbar = tk.Scrollbar(self.lf_message, orient = 'horizontal')# HORIZONTAL 设置水平方向的滚动条,默认是竖直
253         self.xScrollbar.pack(side = 'bottom', fill = 'x') 
254         # 创建文本框,wrap 设置不自动换行
255         self.message_out = tk.Text(self.lf_message, width = 100,
256                                    bg='Black',fg='DarkViolet',
257                                    yscrollcommand = self.yScrollbar.set, xscrollcommand = self.xScrollbar.set, wrap = 'none')
258         self.message_out.pack(anchor='center')
259 
260     def TextUpdate(self,text):
261         print('Text update!
')
262         self.message_out.insert(tkinter.END, text)  
263         self.message_out.see(tkinter.END)
264         self.message_out.update()
265     
266     def TextClear():
267         print('Text clear')
268         self.message_out.delete('1.0','end')
269         
270     def work(self):
271         print('Message tab')
272 
273 ###########################################################################################
274 
275 root = tk.Tk()
276 root.title('tuning拍图小助手V1.0')
277 width = 600
278 height = 480
279 screenwidth = root.winfo_screenwidth()  
280 screenheight = root.winfo_screenheight()  
281 size = '%dx%d+%d+%d' % (width, height, (screenwidth - width)/2, (screenheight - height)/2)
282 root.geometry(size) # width*height + pos_x + pos_y
283 
284 root.columnconfigure(0, weight=1)
285 root.rowconfigure(0, weight=1)
286 
287 content = tk.Frame(root)
288 content.grid(column=0, row=0, sticky=('N', 'S', 'E', 'W'))
289 app = Setting(content)
290 sence = Scene(content)
291 control = Control(content)
292 calculate = Calculate(content)
293 app.work()
294 
295 content.columnconfigure(0, weight=3)
296 content.columnconfigure(1, weight=3)
297 content.columnconfigure(2, weight=3)
298 content.columnconfigure(3, weight=1)
299 content.rowconfigure(2, weight=1)
300 
301 sence.work()
302 control.work()
303 calculate.work()
304 sence.SceneSelect()
305 
306 root.mainloop()
View Code

 后期展望:

  目前只是完成了一个简单的GUI界面,并且一些基本的操作,但是逻辑部分还没有衔接上,然后找BUG优化,美化布局这些,然后打包生成exe文件。

(未完待续,后续更新!······)

原文地址:https://www.cnblogs.com/qiabaowei/p/9502836.html