[原創]-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\n')
181         global SavePicName
182         os.popen("adb remount").read()+'\n'
183         StOpenCamera = os.popen("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA").read()+'\n'
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\n')
191         StOpenCamera = os.popen("adb shell input keyevent 4").read()+'\n'
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 \n')
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()+'\n'+os.popen("ping -n 6 127.1 >nul").read()+'\n'+os.popen("adb pull "+RawPath+" "+SavePicPath).read()+'\n'
205             print("Choosen RAW\n")
206         else:
207             StOpenCamera = os.popen("adb shell input keyevent 27").read()+'\n'+os.popen("ping -n 6 127.1 >nul").read()+'\n'+os.popen("adb pull "+JpgPath+" "+SavePicPath).read()+'\n'
208             print("Choosen JPG\n")
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')+'\n')
224         else:
225             print (os.popen("adb shell rm "+JpgPath+'*.jpg')+'\n')
226         
227     def ClearPicture(self):
228         print ('Clear raw in phone \n')
229         g_cmd_out = os.popen("adb remount").read()+'\n'
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!\n')
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文件。

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

 


免責聲明!

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



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