get paid

Get paid for the tasks you do online

2019年12月17日 星期二

2019年11月17日 星期日

windows remote 執行 Linux GUI

因為 Tx2 是 Linux 的 之前重 Mac , Liunx 都可以 用 ssh -X

來遠端執行, 但 windows 卻不行

但只要安裝 xming 就可以了

https://blog.tomy168.com/2017/06/windows8-puttylinux-guixmingx11.html

2019年11月11日 星期一

TX2 JetPack 4.2 之 open cv 3.4 與 Tensor Flow 1.16 安裝

此次有個專案 需要用到 Tx2 , 但目前 NV 的 刷機程式 跟 1 年前的不一樣
花了兩天 try and error 才算搞定. 這邊做個紀錄

首先要現有 一台 ubuntu . NV 的 SDK manager 只能安裝在 ubuntu 特定版本上

PS . 不建議用 VM , 所以我就用我的就 MacBook Pro (2012) 改成的 ubuntu

下面的網址寫得很清楚了

https://medium.com/@yanweiliu/nvidia-jetson-tx2學習筆記-一-3dab5640968e

但我在第三步時改成 automatic setup , 也就是說 用 SSH 的方式
因為不是用公版 製造商沒有告訴我如何進入 recovery mode.

所以在此之前要確定 Tx2 IP address 與必須要跟 ubuntu PC 同網段

完全刷完 大約要 1 小時

NV 官方有推出 script 可以安裝 open cv 4.0 , 但 CV 4.0 目前很多不資源

之前寫的 code 都是 3.4 版 open cv 與 1.12 的 tensor flow

所以參考JK Jung

JK Jung 是 Tx2 的大神
之前都是參考他的方法 但沒注意那是 再 JetPack 3 之下
JetPack 4 要用新方法

https://jkjung-avt.github.io/opencv-on-nano/

下載外 script 後 要把 cuda_arch 改成 CUDA_ARCH_BIN="6.2"   

約 2 小時就可以 update python numpy , opencv 3.4 了

再依他的介紹 install Tensorflow , 但這步驟 要花 12 小時

https://jkjung-avt.github.io/build-tensorflow-1.12.2/

之後再 install 自己會用到的 package 即可


2019年11月10日 星期日

Adlink Tx2 Box

這次為了客戶的辨識專案, 買了一台 Tx2 . 

此次用 Adlink 的主要原因是看到他的散熱片很大 
之前用一家的 機殼非常燙 

廠商交貨的kernal 太陽春了 只能自己update 

有空來介紹一下 如何 update 最新版的 code

2019年10月10日 星期四

一直想做 pyqt5 的 教學影片 , 但一直沒空

剛好趁連假 用最簡單方式 介紹 pyqt 的 hello world.


https://www.youtube.com/watch?v=oNzKoUCAX3I

有興趣的可以訂閱 分享

我會陸續更新

2019年9月7日 星期六

Python 教學 ---字串處理

字串相加與列印

str3 = str1 + ' ' + str2 # 字串連接 print(str3) #列印第二個字元 print(str3[1]) #重 0 開始計算

常用字串函數

upper() # 轉成大寫
rjust() # 右邊填空白字元




Python 教學--數字處理

基本運算

x=99 print(x) print(x + 1) # 加法 print(x - 1) # 減法: print(x * 2) # 乘法: print(x / 2) # 除法: print(x // 2) # 整數除法 print(x % 2) # 餘數: print(x ** 2) # 指數:

 位移

y=5 print (bin(y)) # y 的二進制 print(y<<1) print(bin(y<<1))

布林運算


print( x == y) print( x!= y) print(x > y)




Python 教學 --- Python 基礎知識 2


整數 int a=10
浮點數 float b=3.14
負數 complex c=1+2j
字串 str d=‘python’





Python 教學 --- Python 基礎知識 1

Python 基礎知識

Python 使用縮排(Indentation)來管理程式區塊
所以不能任意縮排, 需要對齊
使用 #來做註解

Python 開發的好習慣

正確縮排
所有的變數命名都要有意義
做註解






python 教學 ---- What is Python

What is Python

What is Python

Guido van Rossum 1991 年開發完成是一種直譯程式語言
開源 , 免費的程式語言
設計哲學是「優雅」、「明確」、「簡單」
可讀性和簡潔的語法,開發容易,
豐富的模組,減低開發時間
被業界廣泛使用(Google, Banks …)

Python Environment

Anaconda 是最廣泛使用的開發環境
已經包含Python 直譯器與常用的Libraries

Anacoda 下載
https://www.anaconda.com





2019年8月8日 星期四

nohup 指令

再 GCP 要 常常讓指令在背景執行, nohup 是會常用到的指令


https://www.opencli.com/linux/nohup-background-execute-command


別人寫的網頁 我做個紀錄

UBEAR 信用卡優惠計算

前幾天玉山推出了 新的信用卡 ubear , 雖然有8 % 的超商回饋, 但有200元的限制
超過 我要改刷 Pi

於是快速寫了一個 python flask 小程式放在自己的網路上紀錄刷了多少



source code 如下, html 我就不貼了 很短


from flask import Flask
from flask import render_template,request,redirect, url_for,flash
from datetime import datetime
import time



totalNum = 0
numList = []

app = Flask(__name__)


@app.route('/input', methods=['GET'])
def getdata():
    global totalNum
    global numList
    return render_template('input.html',totalNum=totalNum, numList=numList)

#
@app.route('/input', methods=['POST'])
def submit():
    global totalNum
    global numList
    if request.form.get('clear'):
        totalNum=0
        numList =[]

    else:
        number = request.form.get('numbers')

        print(type(number))
        import time

        localtime = time.asctime( time.localtime(time.time()) )

        moneyRec = "NT " + number +"      " + localtime
        numList.append(moneyRec)
        totalNum = int(number) + totalNum
    return render_template('input.html',totalNum=totalNum, numList=numList)

if __name__ == '__main__':
    app.run(host= '0.0.0.0' , port=1000, debug=False)

2019年7月7日 星期日

nvdia Jetson OpenCV Install

Nvdia 內建的 OpenCV 版本太舊了 , 且只有在 python2 下

為了裝 3.6 版 花好的時間 測試不少人寫的 script

這邊做一下紀錄


首先 follow

https://jkjung-avt.github.io/opencv-on-nano/

用 script install , 但 install 發現 python3 下還是不能 import

從父安裝很久才發現 是要 ln

所以先

sudo find / -name "cv2*"

找到 cv2.cpython-36m-aarch64-linux-gnu.so

再workon 到你的環境

用 ln -s  cv2.cpython-36m-aarch64-linux-gnu.so  的完整位置就可以了

為了這個花了我一天的時間

下面是另一個大師寫的 不過他是用原本舊版的 on board opencv

https://chtseng.wordpress.com/2019/05/01/nvida-jetson-nano-初體驗:安裝與測試/

2019年7月5日 星期五

Nvidia Jetson Nano 設定

前天拿到了一個 Jetson Nano 的開發版

這邊紀錄有用到的網頁

https://www.pyimagesearch.com/2019/05/06/getting-started-with-the-nvidia-jetson-nano/

https://chtseng.wordpress.com/2019/05/01/nvida-jetson-nano-初體驗:安裝與測試/



2019年5月12日 星期日

如有用 python 讀取 IP Cameras

讀取 IP Cameras 的方法非常簡單

可以直接使用 Open CV package

import cv2 # ip camera 的擷取路徑 URL = "rtsp://admin:admin@192.168.1.1/1" # 建立 VideoCapture 物件 ipcam = cv2.VideoCapture(URL) # 使用無窮迴圈擷取影像,直到按下Esc鍵結束 while True: # 使用 read 方法取回影像 stat, I = ipcam.read()

python 有關 SQL Lite multi-thread

最近會用到 SQL Lite multi-thread , 主要是用在 TCP server 端

server 會同時收到很多的連線, 這是就要用 multi-thread 來處理了

下面是別人寫的SQL Lite multi-thread

這面先做紀錄

https://scar.tw/article/2012/09/12/sqlite3-multi-thread-in-python/

2019年5月10日 星期五

python TCP 心得

今天遇到一個 tcp 問題 , 有時 server 端會同時收到 client 送來的兩筆之料
檢查了 code 沒有發現問題 卡關了很久

google 才知道 是 TCP 的問題 , 如果資料都是小封包, 且連續傳送 TCP 會主動將兩封包合併傳輸, 以增加網路效率
解法 有兩個 1 是 delay 0.4 sec 以上, 我有試過 0.1 還是有機會發生這狀況
另一個 是 改用 UDP

下面是別人的回覆

https://stackoverflow.com/questions/39931611/python-socket-recv-doesnt-get-every-message-if-send-too-fast

細節可以查

Nagle's algorithm

2019年3月3日 星期日

python Pyqt memory leak

最近檢查code 發現 pyqt 使用的 matplotlib 暫用的 memory 越來越大
應該是 memory leak ...

有空改用 pygraph 試試可不可以解決

2019年2月27日 星期三

python memory

python memory issues blogs

http://terrence.logdown.com/posts/700111-python-track-memory-usage
https://www.codetw.com/ceplqhk.html


https://mg.pov.lt/objgraph/



pyqt good blog
http://ogc-daily.blogspot.com/2009/04/pyqt-part-1-introduction.html

2019年2月26日 星期二

Linux -- add swap space

最近發現 Tx2 上的 python code 跑一兩天會被 OS killed , 看 log 是 out of memory ...

於是增加 swap 試試

下面是別人寫的 增加 swap 的方法

https://shazi.info/linux-oom-killer-kernel-out-of-memory-killed-問題處理-手動增加動態-swap/

https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04

2019年2月8日 星期五

python Line Push Message APi

因為工作需要 study 一下 Line API

https://medium.com/life-of-small-data-engineer/初次嘗試-line-bot-sdk-eaa4abbe8d6e

上面是別人寫的, 照做就完成了 很簡單


PyQt5 不同平台有小差異

最近因工作需要在不同平台跑 PyQT5 , 包含 Windows, Mac , Linux , embedded Linux (Tx2)

但發現code run 起來沒有 error , 但是顯示是是乎有點差異

等有空再詳細測試

Python 心得

因為工作需要再每天固定時間 發送 Line Message

每想自己寫, 但後來想找找有沒有package 可用
果然找到好用的package 叫 APScheduler

https://apscheduler.readthedocs.io/en/latest/userguide.html

他有很多功能, 我只試過我要的功能就是固定每天特定的時間執行特定功能

code 如下
day_of_week='0-6' (星期一到日) 記得是從0開始 每天 19 點 33 分 執行 showDate

很簡單吧


def showDate():



if __name__ == '__main__':

    scheduler = BlockingScheduler()
    scheduler.add_job(showDate, 'cron', day_of_week='0-6', hour=19, minute=33)
    scheduler.start()





2019年2月7日 星期四

PyQt5 教學 --- QCheckBox 使用

Check Box 主要用來製作如 To do List 等應用

使用上也非常簡單
使用QCheckBox 宣告 checkbox , 後面再帶checkbox
就可以定義一個 checkBox ,

cb1 = QCheckBox('Python', self)

之後可以用 clicked.connect , 或是 stateChanged.connect , 來建立信號

當然最重要的是要知道 box 是否被enable 或disable
因為 clicked 或是 stateChanged 都會發出信號

可以使用 isChecked() 來判定是否被 check. 如果是 check return True

使用 .toggle() 則一開始就會被 check

下面是sample code

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QCheckBox


class Windows(QMainWindow):

    def __init__(self):
        super().__init__()

        cb1 = QCheckBox('Python', self)

        cb.move(20, 20)

        cb2 = QCheckBox('C++', self)
        cb2.move(20, 40)

        self.cb3 = QCheckBox('Java', self)
        self.cb3.move(20, 60)
        self.cb3.toggle()

        self.cb3.clicked.connect(self.cb3click)
        self.setGeometry(50,50,320,200)
        self.setWindowTitle("Checkbox Example")

        self.show()


    def cb3click(self):
     
        if self.cb3.isChecked():
            print("Java is selecsted")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Windows()
    sys.exit(app.exec_())

當然實際應用會不會這們簡單, 之後再慢慢寫

2019年1月31日 星期四

PyQT5 教學--- QComoBox , 下拉式選單

下拉式選單也是很常用的UI元件

使用方法也很簡單, 比較不一樣的是觸發信號與槽的處理方法

首先要定義QComboBox ,

combo = QComboBox()

之後是用 addItem 加入選單內容
combo.addItem("Python")

再來定義觸發訊號與槽函數
combo.activated[str].connect(self.onChanged)

最後寫槽函數內容, onChanged 是槽函數
這裡要注意一下,Combo 的訊號跟其他不太相同多了[str], 所以會把addItem 的內容帶入槽函數

所以訊號後面呼叫槽函數的地方不需要再帶入參數
但槽函數需要加入參數, 如下
def onChanged(self, text):

其中 text 就是選擇的下拉式選單內容如Python

完整 code 如下

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QComboBox, QPushButton

class window(QMainWindow):

    def __init__(self):
        super().__init__()

        combo = QComboBox(self)
        combo.addItem("Python")
        combo.addItem("C++")
        combo.addItem("JS")

        combo.move(50, 50)

        self.qlabel = QLabel(self)
        self.qlabel.move(100,100)

        combo.activated[str].connect(self.onChanged) #Signal

        self.setGeometry(300,100,320,200)
        self.setWindowTitle("QCombo Example")
        self.show()

    def onChanged(self, text):
        self.qlabel.setText(text)
        self.qlabel.adjustSize()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = window()
    sys.exit(app.exec_())



2019年1月30日 星期三

PyQT5教學 QTimer 應用計時器

上一篇簡單的應用了 QTimer 來做計時器, 再來我們增加兩了 button : Start , Stop

當按Start 開始計數, 和下stop 就停止

很簡單我們只要把 timer.start 與 timer.stop 加入 button 的 slot function 中即可

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QGridLayout, QWidget,QPushButton
from PyQt5.QtGui import QPixmap, QImage,QFont
from PyQt5.QtCore import QTimer

class window(QWidget):
    def __init__(self):
        super().__init__()
        self.label = QLabel(self)
        self.label.setText("0")
        self.label.setGeometry(300,100,200,200)
        self.label.setFont(QFont("Roman times",100,QFont.Bold))
        self.setGeometry(500,300,700,500)
        self.setWindowTitle("PyQT Timer Demo")
        self.timer=QTimer(self)
        self.timer.timeout.connect(self.run)
        # self.timer.start(1000)
        self.total = 0
 #add start Btn
        self.startBtn = QPushButton(self)
        self.stopBtn = QPushButton(self)
        self.startBtn.clicked.connect(self.startCount)
        self.startBtn.setGeometry(50,400,100,50)
        self.startBtn.setText("Start")

        self.stopBtn.clicked.connect(self.stopCount)
        self.stopBtn.setGeometry(500,400,100,50)
        self.stopBtn.setText("Stop")

#Start the Timer
    def startCount(self):
        self.timer.start(1000)
# Stop the Timer
    def stopCount(self):
        self.timer.stop()

    def run(self):

        self.label.setText(str(self.total))
        self.total+=1


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = window()
    ex.show()
    sys.exit(app.exec_())

PyQT5 教學 --- QTimer 應用


Timer 是 UI 很重要的一個功能, 因為UI 常常會因為時間定期自己更新畫面, 如camera
camera 可以想像成 每幾個 ms 會產生一個圖案 (image) 

所以需要每幾個 ms 去處理一次畫面

另外一個更常用的是計時器, 下面我先demo  一個簡單的記事功能, 之後會再慢慢增加功能
主要是讓大家了解 QTimer 的應用

QTimer 這個 class 其實很簡單, 當定義好QTimer 後, 每隔設定的時間會發出signal 到指定的Slot

另外我們會新使用一個PyQT的class 叫 QFont,  用來設定字型與大小

下面的 code 就是簡單的計時器

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QGridLayout, QWidget
from PyQt5.QtGui import QPixmap, QImage,QFont
from PyQt5.QtCore import QTimer

class window(QWidget):
    def __init__(self):
        super().__init__()
        self.label = QLabel(self)
        self.label.setText("0")
        self.label.setGeometry(200,100,200,200)
        self.label.setFont(QFont("Roman times",100,QFont.Bold)) #設訂字體
        self.setGeometry(500,300,700,500)
        self.setWindowTitle("PyQT Timer Demo")

        self.timer=QTimer(self) # 呼叫 QTimer 
        self.timer.timeout.connect(self.run) #當時間到時會執行 run
        self.timer.start(1000) #啟動 Timer .. 每隔1000ms 會觸發 run
        self.total = 0 #初始 total


    def run(self):

        self.label.setText(str(self.total)) # 顯示 total
        self.total+=1 #Total 加 1 


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = window()
    ex.show()
    sys.exit(app.exec_()) 


QTimer 一但 start 就會一直觸發事件, 並不是只出發一次
所以如有需要要自己 stop 

QTime 的時間單位是 ms , 與python 常用的timer 不同 timer 單位是 seconds

另外 QTimer 執行的時間要很小心, 如果 Slot 槽函數需要較長的執行
時間時, QTimer 的 時間就不要設太短, 
還有如果Timer 的時間設太短的話因為一直被觸發, 這時影響到其他功能的執行



PyQt5 教學 -- 加入圖片 QPixmap

將照片加入 GUI 也很簡單, 首先建立一個 windows 的 class , 再將 照片使用 QPixmap 加入

QPixmap 是 PyQt5 package 中屬於 QtGui 的一個物件 , 前面用到的都是 QtWidgets 的物件
所以QPixmap 主要是處理GUI 的

並建立一個 QLabel , 前面我們都是文字輸入label , 但這裡我們可以輸入照片如此就完成了

程式如下

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QGridLayout, QWidget
from PyQt5.QtGui import QPixmap

class window(QWidget):

    def __init__(self):
        super().__init__()

        self.im = QPixmap("Lena.png") #要確認 Lena.png 路徑
        self.label = QLabel(self)
        self.label.setPixmap(self.im) #將 image 加入 label
        self.label.setGeometry(60,60,500,500) # 大小
        self.setGeometry(50,50,600,600)
        self.setWindowTitle("PyQT show image")
 

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = window()
    ex.show() #將show 寫到外面
    sys.exit(app.exec_())


這code 是不是很精簡..  更前面相比我把 show 寫到外面, 因為我們用的是 class
所以之後可能會讓其他程式 call 他, 所以有可能我們會暫時把UI disable , 如寫道外面就可以很容易的控制他是不是要顯示

當然如除了加入照片也可以用在影片還要 IP Cameras 或是 Web Cam
後面會慢慢介紹


註: 1.show function 是繼承 QWidget 來的 2. Lena.png 是影像處理很常看到的照片




PyQT5 教學 --- QCalendar 使用 Class

上一篇有介紹到 Qcalendar, 但並沒有使用 Class 來定義主視窗 ,
這篇就來介紹如何使用 Class 定義主視窗, 其實 code 跟function 差不多

基本概念很間單, 我們先定義一個主視窗的 class .  這個class 繼承QWidget, 或 Qmessage class
之後我們再將視窗內會用到的元件如 button , label 加入到 class 內

程式解說如下

# import necessary package

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QCalendarWidget
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import Qt

#定義主視窗 叫 windows 的 class, 這個class 繼承QWidget
#這個跟 上一篇 的 win = QWidget()  意思差不多

class windows(QWidget):

    def __init__(self):  #用來初始化這個類別會用到的變數

        super().__init__()  # 這個 class 可以使用父類別的function

        self.calendar = QCalendarWidget(self) # 將 QcalendarWidget 加入此視窗
     
這個部分跟 function 很像 只是前面變數, 我們要加 self. 讓這變數可以在這 class 內使用
使用function 時 後面我們帶入要加入的視窗物件, 但我們已經在此物件內了, 所以直接使 用self 來代表此物件

        self.calendar.setGeometry(50,50,300,300) #設定位置
        self.calendar.selectionChanged.connect(self.showdate) #產生日曆選擇改變的signal.
     
 之前使用 function 時, 我們必須要把 calendar 這個物件一並傳入, 但使用class 時只要function 是在同一個 class 中就可以不用


        self.setWindowTitle("PyQt Calendar Example")
        self.setGeometry(50,50,400,400)
     
        self.show() #顯示此 windows

    def showdate(self): # 記得要加 self
        selectDay = self.calendar.selectedDate() #確認被選的日期,  記得要加 self

selectDay 是 PyQT 日期格式, 但如果我們是要用這日期給 SQL 處理時須轉換

        print("pyQT day",selectDay)
加入toString(Qt.ISODate) 就會變成string格式, 之後可以給 datetime package 處理
        print("normal day", selectDay.toString(Qt.ISODate))

selectDay 只會在 def showdate 這個function 內使用, 所以可以不用加self.  但如果此class 內其他地方會用到, 要在 init 內定義, 並且變數前面要加 self



if __name__ == '__main__':
    app = QApplication(sys.argv) #改寫在外面
    win=windows()
    sys.exit(app.exec_()) #改寫在外面

QApplication 如果寫在class 裡面會出錯, 因為要先有QApplication 才成有 Qwidget, 我們的windows class 是承接 Qwidget 的所以當然放在外面, 所以 sys.exit 也一並放在外面

執行結果



使用class 事不是相對於 function 更容易讓別人瞭解

我想很多人會對 class 很害怕是因為他們覺得很 繼承等很複雜很可怕
但其實經過講解其實不難, 直接寫成 code 就會發現 class 很好用

當然 上面的應用只用到 class 部分的好處, 這些好處當視窗變多後就變很重要
之後我會慢慢提到

我之所以會寫這Blog 主要是想一步一步介紹




2019年1月29日 星期二

PyQT5 教學 - QCalenderWidget

PyQT 為何很多人用了開發 UI , 一個原因是因為 它包含了很多實用的 Widget , Calendar 就是其中一個 , 這省了很多開發時間, 不然自己寫一個日曆 是會瘋掉的

Calendar 物件用法跟前面的 button 差不多, 但多了一些日期的處理

下面這個例子會先用 function 來做處理, 使用上沒有問題, 但這不是很好的作法, 因為當使用者發出改變選擇的日期的訊號時, 會需要把 calendar 這個物件一起當參數傳給槽函數

這對未來要修改 code 時會很不容易 且如果很function 一直被呼叫, calendar 會被一直帶入 這是很好資源的, 所以往後的程式會漸漸地以 class 為主, 讓大家漸漸習慣 class 的使用.

#import package 其中 Qt 是用來做日期的轉換的

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QCalendarWidget
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import Qt
from functools import partial
def window():
    app = QApplication(sys.argv)
    win = QWidget()
    calendar = QCalendarWidget(win)
 
    calendar.setGeometry(50,50,300,300)
    calendar.selectionChanged.connect(partial(showdate,calendar))
# 當發出日期選擇時發出訊號到 showdate 槽並帶入 calendar 物件做參數

    win.setWindowTitle("PyQt Grid Example")
    win.setGeometry(50,50,400,400)
    win.show()
    sys.exit(app.exec_())

def showdate(calendar):
    selectDay = calendar.selectedDate() #確認被選的日期
# selectDay 是 PyQT 日期格式, 但如果我們是要用這日期給 SQL 處理時須轉換

    print("pyQT day",selectDay) #
#加入toString(Qt.ISODate) 就會變成string格式, 之後可以給 datetime package 處理
    print("normal day", selectDay.toString(Qt.ISODate))

if __name__ == '__main__':
   window()


是不是很簡單

PyQT5 教學 --- 訊號與曹進階2

上一篇有提到訊號呼叫槽 函數時不能帶參數, 但以我們 9 9 乘法表的例子
我們一定要帶參數啊, 不然就要寫很多訊號跟槽了
之前不知不能帶參數 花了很多時間 try and error.
這也是為何我要寫這個 Blog 的原因之一

解法其實很簡單,  網路上有人提到用lambda , 但我比較喜歡用partial.

partial 是 functools 下的一個函數

只要將要呼叫的function ,與 參數 改用 partical 包起來就可以了

k.clicked.connect(partial(showMessage,i,j))

完整程式如下
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout, QPushButton,QMessageBox
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
from functools import partial #import partial

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   grid = QGridLayout()
   dict =[]

   for i in range(0,9):
      for j in range(0,9):
         k = QPushButton(str(i+1)+"*"+str(j+1))
         grid.addWidget(k,i,j)
         print(k)
         k.clicked.connect(partial(showMessage,i,j)) #呼叫showMessage 並帶入i, j


   win.setLayout(grid)
   win.setWindowTitle("PyQt Grid Example")
   win.setGeometry(50,50,200,200)
   win.show()
   sys.exit(app.exec_())

def showMessage(i,j):
    x=(i+1)*(j+1)
    msgBox = QMessageBox()

    msgBox.setText("{} * {}= {}".format(str(i+1),str(j+1),str(x)))
    msgBox.setWindowTitle("Signal & Slot ")
    msgBox.setStandardButtons(QMessageBox.Ok)
    # msgBox.buttonClicked.connect(msgButtonClick)
    msgBox.exec()
    msgBox.show()


if __name__ == '__main__':
   window()

結果如下



PyQT5 教學 --- 訊號與曹進階

上一篇有提到如果有多個按鈕, 他要觸發相識的東西有需要一個個寫對應的訊號 跟 槽嗎

上一篇我們設計了 81 個按鈕, 所以會產生81 個訊號, 如果對應的結果是完全相同當然只要寫一個槽就好了
但如果對應的結果只是相似, 但不完全要同要如何處理呢?

我們先來demo 要如何產生 81 個訊號, 這部分是我 try 很久的



#import 用到的 package

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout, QPushButton,QMessageBox
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

#定義 主windows
def window():
   app = QApplication(sys.argv)
   win = QWidget()
   grid = QGridLayout()
   dict =[]

   for i in range(0,9):
      for j in range(0,9):
         k = QPushButton(str(i+1)+"*"+str(j+1))
         grid.addWidget(k,i,j) #將button 加入 widget
         print(k)
         k.clicked.connect(showMessage)  #將 push button 訊號指向 show Message 槽

   win.setLayout(grid)  # 將 grid 加入 windows
   win.setWindowTitle("PyQt Grid Example")
   win.setGeometry(50,50,200,200)
   win.show()
   sys.exit(app.exec_())


#Show Message 的內容跟前幾篇提到的 QMessage 相同

def showMessage():
    print("clicked")
    msgBox = QMessageBox()
    msgBox.setIcon(QMessageBox.Information)
    msgBox.setText("Button is clicked")
    msgBox.setWindowTitle("QMessageBox Example")
    msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
    # msgBox.buttonClicked.connect(msgButtonClick)
    msgBox.exec()
    msgBox.show()


if __name__ == '__main__':
   window()



上面的 Signal 與 Slot ,看起來很簡單吧, 但是為何我會 Try 很久呢?
主要是因為我把 clicked.connect  與 show Message 放在另一個程式, 這個時候我的
 k.clicked.connect 中的 K 需要把它指定為QPushbutton 才能, 而不能只是一個變數
另外外部呼叫的所以每一個 button 都要有一個變數, 不然他不知道要指向哪裡

之所以我會把Signal 與 Slot 是因為 UI 是用 QT Designer 產生的, 且 Signal 與 Slot 教父複雜
所以想分開寫

但如果可以想寫一起, 會簡潔很多

另一個原因是 Slot 其實有限制, 這邊呼叫的都是相同的內容
所以簡單很多,
如果是要用一個Slot function , 帶不同的參數,以對應不同的結果那就要小心了

因為 呼叫slot 時不能帶參數的, 這跟一般 function 呼叫不同

但解法很簡單 下一篇會解釋



https://www.amazon.com/gp/product/1449355730/ref=as_li_tl?ie=UTF8&tag=sammyoython-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1449355730&linkId=080ac10887e654d6eadc51f44a1c5774

PyQT5 教學 --- Grid (QGridLayout)

QGridLayout 是個widget 的排列工具,  他讓widget 可以像 excel 這樣樣的排成格子狀
雖然大多數的UI Layout 都可以使用之後會介紹的QT Designer 來製作, 但如果要再視窗加入很多按鈕, 或是要加入圖片或是之後會提到的 video streaming , QGridLayout 就是很重要的工具

要建立QGridLayout 物件很簡單

grid= GridLayout() 

告訴 windows 使用 grid 

win.setlayout(grid)

將 widget 加入 grid , 這裡的 widget 可以是 Qbutom 物件 或是 QLabel 等等

grid.addWidget(widget, col, row) 


非常簡單吧

另外也會使用 for 迴圈建立 QPushButton, 這了一來方邊很多, 例如我們要建立 9x9 不需要
自己定義 81 的 button 

#import 所需 package
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   grid = QGridLayout()

# 使用兩個 for 迴圈定義 button 物件並加入 grid 
# button 內顯示的字串要加1 才會重一開始

   for i in range(0,9):
      for j in range(0,9):
         grid.addWidget(QPushButton(str(i+1)+"*"+str(j+1)),i,j)

   win.setLayout(grid) # 將 grid 加入 windows 物件
   win.setWindowTitle("PyQt Grid Example")
   win.setGeometry(50,50,200,200)
   win.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   window()

顯示結果如下

看到這解果可能有人會說 按鈕要如何運作? 
難道Signal and Slot 要 一 個個 寫嗎?
還是依樣可以 用 for 來寫呢?


下一篇說分明




2019年1月27日 星期日

PyQT5 教學 -- QLineEdit

QLineEdit 也是很常用的物件, 它允許使用者輸入資料
這邊就用一個範例當使用者輸入時 會在下面用 QLable 對應輸出

程式如下
為了讓大家漸漸了解 物件的寫法, 下面就改用物件的方式
為何會用物件呢 ? 當程式功能越來越多, 就會把 UI 跟 計算部分分開成不同py 欓
如果UI 是用class 寫得要呼叫就會比較容易

首先當然是 import package..


import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QPushButton


再來就是建立一個 example 物件這個物件繼承了 QMainWindow 這個 pyqt 物件
這個我們之前寫法 example =  QMainWindow() 意是差不多
但當我們要對這物件作很多處理時, 如加入很多 button 用 class 定義的方式比較容易修改
也比較容易理解


class Example(QMainWindow):

# 再來我們要初始化Example 這個物件

    def __init__(self):
        super().__init__()   # 表示 Example() 可以調用父類別的function

        self.lineEntry = QLineEdit(self) # 加入QLineEdit 到此物件, 下面會在解說
        self.lineEntry.move(16,16) # 位置
        self.lineEntry.resize(200,40) # 大小

        self.qlabel = QLabel(self) #加入QLabel 到此物件
        self.qlabel.move(16,64)# 位置
        #當 QLineEdit 物件的內容修改時, 執行 onChanged 這個 function
        # 因為 onChange 是在這個 class 內, 所以前面要加 self.
        self.lineEntry.textChanged.connect(self.onChanged)

        self.setGeometry(50,50,320,200)# 位置
        self.setWindowTitle("QLineEdit Example")# 大小
        self.show() # 顯示

# QLine Edit 的曹, 當 QLineEdit 文字有改變時會呼叫onChanged, 並帶入文字到 text 中
# 當 123 輸入, text 就是 123

    def onChanged(self, text):

        text = "Your Enter is " + text # 可以對文字再處理
        self.qlabel.setText(text) # 將 text 秀在 QLabel 上
        self.qlabel.adjustSize()

#下面的部分跟 function ㄧ樣

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


之前我們再 Qwiget 內在加入一個 物件時
寫法如下
lineEntry = QLineEdit( 主物件) 但我們已經在主物件內了
寫法就前面加 self , 主物件也改成 self ,變成如下
self.lineEntry = QLineEdit(self)



PyQT5 教學 -- QMessage Box 教學-2

上一篇提到的 QMessage 用到的是一個單獨的QMessage 物件
實際應用中並不會這麼單純,
實際應用中一定是有個事件被觸發然後跳出 QMessage
最常見的是一個 button 被按下 , 然後就跳出 QMessageBox 提示

所以下面的用這例子來做範例
這個範例我們會用 function 方式 , 而先不用物件的方式, 但兩者其實差異不大

首先先 define 兩個 function, 一個 function 是顯示我們的主 GUI
主UI 上會有 一個 buton 物件
看看下面的程式 def window() 內跟上面寫的單一功能其實是一樣的
當 button 被按下就會呼叫 showDialog() function
最後加入
if __name__ == '__main__':
   window()

讓程式一開此就執行 window() function
是不是很簡單

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   button1 = QPushButton(win)
   button1.setText("Show dialog!")
   button1.move(50,50)
   button1.clicked.connect(showDialog)
   win.setWindowTitle("Click button")
   win.show()
   sys.exit(app.exec_())

def showDialog():
   msgBox = QMessageBox()
   msgBox.setIcon(QMessageBox.Information)
   msgBox.setText("Message box pop up window")
   msgBox.setWindowTitle("QMessageBox Example")
   msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
   msgBox.buttonClicked.connect(msgButtonClick)

   returnValue = msgBox.exec()
   if returnValue == QMessageBox.Ok:
      print('OK clicked')

def msgButtonClick(i):
   print("Button clicked is:",i.text())

if __name__ == '__main__':
   window()


PyQT5 教學 -- QMessage Box 教學

QMessageBox 其實就是 pop up message , 彈跳視窗. 可以pop up 重要 message.


# import 需要的 package
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot


app = QApplication(sys.argv)
msgBox = QMessageBox()  # 建立一個 message Box 對話框


msgBox.setIcon(QMessageBox.Information) # msgBox 加入一個 "information" icon

上面這個 icon 就是下面紅框框內的 驚嘆號 ( 紅框框事後製)



msgBox.setText("Message box pop up window") # 加入文字

再QMessageBox 內文字可以直接加入

msgBox.setStandardButtons(QMessageBox.Ok| QMessageBox.Cancel)

加入message標準按鈕 OK .. Cancel..  這是 QMessage 標準的按鈕

#當msgBox執行時 如是 ok 被按下執行 ok clicked
#如是 Cancel  被按下執行 print Cancel clicked

returnValue = msgBox.exec()
if returnValue == QMessageBox.Ok:
    print('OK clicked')

elif returnValue == QMessageBox.Cancel:
    print("Cancel clicked")

msgBox.show() # 顯示 msgBox

#sys.exit(app.exec_()) # QMessageBox 本來就只會顯示一次 只要 Ok 或 canes 被觸發就結束了 , 所以可以不用這行

當然也可以使用訊號與槽 執行 ok 或 cancel button
msgBox.buttonClicked.connect(msgButtonClick) #msgbox ok or cancel 被案下的訊號

msgBox 槽

def msgButtonClick(i): # i 是被案的按鈕
   print("Button clicked is:",i.text()) 

# 如果是 ok 被案則 i.text 是 ok , cancel 被案下則是 cancel


當然也可以在 再 message box 加入 button 物件, 不過如此一來直接用widget 就好了




PyQT5 教學 -- 按鈕(Buttons)的應用

按鈕(Buttons) 是 GUI 中很常用到的元件

按鈕的建置跟上一篇提到很相識, 但多了一個連動的概念以 PyQT 來說就是Signals and Slot
(訊號與槽) 葉就是說當我按了一個 Button ( 發射一個訊號) 要執行哪個動作 (到哪個槽)

直接看範例吧

# import 有用的的 library

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

# 定義 Button1 被觸發時要執行的槽
def button1_clicked():
 print("Button 1 clicked")

# 定義 Button1 被觸發時要執行的槽
def button2_clicked():
 print("Button 2 clicked")

#創建 APP 這個 GUI 
app = QApplication(sys.argv)
#創建一個 Widget 物件
widget = QWidget()
#再 widget windows 內創建一個 Button 物件
button1 = QPushButton(widget)
button1.setText("Button1")  # 建立名字
button1.move(64,32)  # 移動位置
# 當 button1 這個物件發出訊號時( 被按了) 到 button1_clicked 這個槽執行
button1.clicked.connect(button1_clicked)

button2 = QPushButton(widget)
button2.setText("Button2")
button2.move(64,64)
button2.clicked.connect(button2_clicked)

# 訂定 widget 視窗的大小, 名稱
widget.setGeometry(50,50,320,200)
widget.setWindowTitle("PyQt5 Button Click Example")
widget.show() # 顯示 widget
sys.exit(app.exec_())  # 讓視窗循環顯示

執行解果如下

當 button 按下是 會 print
 



PyQT5 教學 -- 顯示 Hello World

















會想要寫一系列的PYQT5 教學 主因是一直沒有找到一本書 從基礎pyqt5 教起
之前買了一本 大陸作者對書, 她把 PYQT 教的很複雜, 讓我一開死有點挫折, 只了一下也沒啊線好的英文書籍 就想到自己把自己心得寫出來

剛好看到 https://pythonbasics.org 有新增 PyQt 介紹 我就打算以此為藍本翻譯給大家

大家寫程式第一步都是 Hello World ...  PyQT 第一步 也來個 Hello Word 吧

首先當然是 import 所需要的

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

上面這都是跑不掉的

再來就是呼叫QApplication , 初始化圖形介面物件
app = QApplication(sys.argv)

呼叫 Qwidget 物件, 並給這個物件一個名字 widget
QWidget 物件又是一個簡單的視窗物件

widget = QWidget()

widget.setGeometry(50,50,320,200)  # 設定視窗位置 (左上X, 左上Y, 右下X, 右下Y)
widget.setWindowTitle("PyQt5 Hello World 測試")
但當我們要加入一串文字時, 並不能直接加入
需要先在 QWidget 裡面加入一個 QLabel 物件,
Qlabel 這物件 就是用來存要顯示的字串, 在這裡就是 Hellow World
所以我們現加入 Qlabel 到 widget 這個視窗物件 , 並給他一個名字叫textLabel

textLabel = QLabel(widget)

#將hello world 寫入 textLabel

textLabel.setText("Hello World!")

# 將 label 移到螢幕 100,85 這個位置
textLabel.move(110,85)

上面的視窗設定完了並不會顯示
需要執行 show() 才會顯示
widget.show()

當然整個圖形介面程式需要執行下面這行才會動作
sys.exit(app.exec_())


完整程式如下
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

app = QApplication(sys.argv)
widget = QWidget()
widget.setGeometry(50,50,320,200)
widget.setWindowTitle("PyQt5 Hello World 測試")
textLabel = QLabel(widget)
textLabel.setText("Hello World!")
textLabel.move(110,85)
widget.show()
sys.exit(app.exec_())

結果


很簡單吧? 之所以GUI 設計有點複雜是因為他用到很多物件的概念, 很多人教也都用物件的叫發來寫, 但針對簡單的 GUI 是不需要把它包成 class 的

當然如果要寫複雜的 GUI 用物件是必須的, 但當你知道基本後 再改成物件形式就很簡單了
這個之後會慢慢教

下面是我的教學影片





2019年1月24日 星期四

Python 地圖視覺化 使用 folium

因為公司有個產品可以傳 GPS location , 於是我用 python 製作了 地圖視覺化

不少地圖視覺 都是單機版的, 要轉成 html 還要一次工
但 folium 就方便很多

http://blog.yeshuanova.com/blog/posts/python-visulization-folium/

上面blog 是別人寫的介紹

2019年1月23日 星期三

python camera 加速

因為 python  一次處理一個 block , 所以這特性當用到 real time streaming 的 cameras 時 會覺得lag , 這時候要用的 thread 來處理

下面是別人寫的範例

https://dotblogs.com.tw/shaynling/2017/12/28/091936

但我最常用的是 PyImageSearch 寫的 library  inutile.video 中的 VideoStream

細節可以參考 pylmagesearch 的 blog


但如果要處理多個 cameras 的 streaming, 光用 threading 是不夠的
因為 threading 的特性  , 實際上只只用到 CPU 的一個核心.

所以就要改用 multiprocessing
有空再來上傳我的 demo code ...

python ZIP 小技巧

zip 是 python 很好用但 用的人卻不多的function

寫 python 時我常常用 zip 把兩個 list 合併成一個 dict ..
 dict 要查群時 會方便很多


hours = [x for x in range(0,24)]

Counts = [int(0) for x in range(0,24)]
hourUpCounts = dict(zip(hours,Counts))
hourDownCounts = dict(zip(hours,Counts))
hourSpeed = dict(zip(hours,Counts))

ChartGPT 學 python 很強喔

 ChartGPT 最近很紅 ,  前一陣子有一些小 module  本來想 google  一下 語法 但發現用 chartGPT 直接請他給 sample code 反而較快 所以只要你有基本 知識 ChartGPT 可以加速你的開發 好用喔