1. 程式人生 > >用Python快速實現一個垃圾分類APP|附帶微信小程式

用Python快速實現一個垃圾分類APP|附帶微信小程式

最近北京開始實行垃圾分類,導致大家對垃圾的研究熱度突然漲高,垃圾們也紛紛表示從來沒有獲得過這麼高的關注度。其實,上海市去年已經開始實行,網上已經有不少成熟的教程了,像什麼《垃圾分類從入門到精通》、《深入淺出垃圾分類》、《垃圾分類你應該掌握的10條基本原則》。這種教程如果我們親自去學顯然不符合程式設計師的個性,作為一個程式設計師,我們應該把這事兒交給機器來做,這樣才能省下更多的時間投入到996中。

扯了這麼多廢話,下面言歸正傳,今天這篇文章主要介紹如何利用現有的工具來實現一個垃圾分類的應用。這個想法是我昨天才有的,今天用了不到一天的時間就完成了,主要做了三個核心內容:

  • 對比現有垃圾分類服務,挑選一個合適並編碼實現
  • 開發桌面版垃圾分類APP
  • 開發垃圾分類微信小程式

上面這三部分第一部分是後端的活兒,其他兩部分都是前端的活兒,所以,我在這三塊沒有太多經驗,基本上是面向搜尋引擎程式設計。雖然我的主業是做大資料的,但我確實想做這樣一個比較有意思的專案,畢竟一個不會後端的前端不是一個好的大資料工程師。

老規矩,先看效果圖,PC版:

![](https://user-gold-cdn.xitu.io/2020/5/11/171ffae52d1311a2?w=1078&h=714&f=gif&s=1879662)

小程式:

![](https://user-gold-cdn.xitu.io/2020/5/11/171ffb16877b21ad?w=320&h=572&f=gif&s=1406229)

附上小程式二維碼,大家可以體驗一下。如果開啟看不到效果可能稽核沒通過,稍微晚點再開即可。

![](https://user-gold-cdn.xitu.io/2020/5/11/171ffd6d7a67327a?w=258&h=294&f=jpeg&s=31150)

這篇文章會貼比較多的程式碼,並且公眾號閱讀起來不是很方便,所以文末我在文末會附上原始碼的獲取方式。(公眾號回覆關鍵字 垃圾分類 即可獲取整篇文章全部原始碼)

那麼,接下來我們進入到具體的細節是如何做的。其實垃圾分類已經開始很長一段時間了,肯定會有一些服務商把垃圾分類的能力通過API的方式開放出來,供大家呼叫。我找了3家簡單對比下供大家參考:

  • 聚合資料(www.juhe.cn):提供文字、影象、語音分類。免費呼叫20次,定價不靈活只能批量購買
  • 天行資料(www.tianapi.com):提供文字、影象、語音分類。文字分類5000次,其他50次,定價按量計費
  • 京東AI開放平臺:提供文字、影象、語音分類。免費,每日5000次

簡單對比了影象分類情況,聚合和天行資料明顯更好,再綜合定價因素最終我決定用天行資料。 下面就來編寫程式碼,將API介面封裝成我們需要的服務,以文字(垃圾名稱)分類介面為例,請求的介面如下

http://api.tianapi.com/txapi/lajifenlei/index?key=APIKEY&word=眼鏡

APIKEY需要到天行網站註冊來獲取,返回的結果如下:

{
  "code":200,
  "msg":"success",
  "newslist":[
    {
      "name":"隱形眼鏡",
      "type":3,
      "aipre":0,
      "explain":"幹垃圾即其它垃圾,指除可回收物、有害垃圾、廚餘垃圾(溼垃圾)以外的其它生活廢棄物。",
      "contain":"常見包括磚瓦陶瓷、渣土、衛生間廢紙、貓砂、汙損塑料、毛髮、硬殼、一次性製品、灰土、瓷器碎片等難以回收的廢棄物",
      "tip":"儘量瀝乾水分;難以辨識類別的生活垃圾都可以投入幹垃圾容器內"
    },
    {
      "name":"眼鏡",
      "type":3,
      "aipre":0,
      "explain":"幹垃圾即其它垃圾,指除可回收物、有害垃圾、廚餘垃圾(溼垃圾)以外的其它生活廢棄物。",
      "contain":"常見包括磚瓦陶瓷、渣土、衛生間廢紙、貓砂、汙損塑料、毛髮、硬殼、一次性製品、灰土、瓷器碎片等難以回收的廢棄物",
      "tip":"儘量瀝乾水分;難以辨識類別的生活垃圾都可以投入幹垃圾容器內"
    },
  ]
}

介面的欄位說明大家可以看官網文件,這裡我就不再贅述了。下面來編寫請求文字分類介面的程式碼:

import base64
import requests


class TxApiService:
    def __init__(self):
        self.appkey = 'xxx'  # 需要換成自己的
        self.text_cls_url_root = 'https://api.tianapi.com/txapi/lajifenlei/index?key=%s&word=%s'
        self.img_cls_url_root = 'https://api.tianapi.com/txapi/imglajifenlei/index'

    def get_text_cls_res(self, garbage_name):
        url = self.text_cls_url_root % (self.appkey, garbage_name)
        response = requests.get(url)

        res = []
        if response.status_code == 200:
            res_json = response.json()
            if res_json.get('newslist'):
                new_list_json = res_json['newslist']
                for item in new_list_json:
                    name = item.get('name')
                    cat = self.garbage_id_to_name(item.get('type'))
                    tip = item.get('tip')
                    ai_pre = item.get('aipre')
                    pre_type = 'None'
                    if ai_pre == 0:
                        pre_type = '正常結果'
                    if ai_pre == 1:
                        pre_type = '預判結果'
                    item_dict = {'name': name, 'type': cat, 'tip': tip, 'pre_type': pre_type}
                    res.append(item_dict)
                return res
            else:
                return None
        return None

    def garbage_id_to_name(self, id):
        if id == 0:
            return '可回收物'
        if id == 1:
            return '有害垃圾'
        if id == 2:
            return '廚餘垃圾'
        if id == 3:
            return '其他垃圾'
        return None

程式碼比較簡單,用Python的requests庫請求垃圾分類介面,並對返回的資料格式化。 下面再來編寫請求影象分類的介面

def get_img_cls_res(self, img_base64):
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    body = {
        'key': self.appkey,
        "img": img_base64,
    }
    response = requests.post(self.img_cls_url_root, headers=headers, data=body)

    res = []
    if response.status_code == 200:
        res_json = response.json()
        if res_json.get('newslist'):
            new_list_json = res_json['newslist']
            for item in new_list_json:
                name = item.get('name')
                cat = self.garbage_id_to_name(item.get('lajitype'))
                tip = item.get('lajitip')
                trust = item.get('trust')
                if trust <= 80:
                    continue
                item_dict = {'name': name, 'type': cat, 'tip': tip, 'pre_score': trust}
                res.append(item_dict)
            return res
        else:
            return None
    return None

函式的引數是影象的base64編碼,請求方式是POST請求,返回值欄位與文字分類略有不同,但思路是一樣的。這兩部分內容其實比簡單,這裡我就不再過多解釋了。

有了資料服務,下面我們就來開發GUI,這裡我用的是tkinter,用它編寫的APP可以執行在Linux、Windows和Mac系統,關於tkinter的使用這裡我不會做過多介紹,不瞭解的朋友自行百度,之前我也沒結果過基本上看網上的教程照貓畫虎。 首選,建立GarbageClassificationApp類,來定義用到的各種元件

import base64
import tkinter

from tkinter import *
import hashlib
import time
from tkinter import filedialog

from TxApiService import TxApiService

class GarbageClassificationApp:
    def __init__(self, tk):
        """
        初始化各個元件
        :param tk:
        """
        self.tk = tk

        # 第一行定義文字分類相關的元件
        self.text_cls_label = Label(self.tk, text="垃圾名:")
        self.garbage_name_text = Entry(self.tk)
        self.text_cls_button = \
            Button(self.tk, text="垃圾名分類", bg="lightblue", width=10, height=1, command=self.garbage_name_cls)

        # 第二行定義影象分類相關的元件
        self.img_cls_label = Label(self.tk, text="垃圾圖片:")
        self.select_file_button = Button(self.tk, text='選擇圖片', command=self.select_pic)
        self.img_cls_button = \
            Button(self.tk, text="圖片分類", bg="lightblue", width=10, height=1, command=self.garbage_img_cls)
        self.img_name_text = Text(self.tk, height=2)
        self.img_name_text.insert(1.0, '未選擇圖片:')
        self.img_name_text['state'] = DISABLED

        # 第三行定義輸出結果相關的元件
        self.cls_result_label = Label(self.tk, text="分類結果:")
        self.output_cls_result_list_box = Listbox(self.tk, width=100, height=30)

        # 初始化 api 服務
        self.api_service = TxApiService()

        self.set_init_window()

再來建立set_init_window函式對各個元件進行佈局

# 各元件佈局
def set_init_window(self):
    self.tk.title("垃圾分類")
    self.tk.geometry('1068x681+350+200')  # 1068x681為視窗大小,+100 +100 定義視窗彈出時的預設展示位置

    # 第一行文字分類各元件的佈局
    self.text_cls_label.grid(row=0, column=0, sticky=E)
    self.garbage_name_text.grid(row=0, column=1)
    self.text_cls_button.grid(row=0, column=2, padx=10)

    # 第二行影象分類各元件的佈局
    self.img_cls_label.grid(row=1, column=0, sticky=E)
    self.select_file_button.grid(row=1, column=1)
    self.img_cls_button.grid(row=1, column=2, padx=10)
    self.img_name_text.grid(row=1, column=3, padx=10)

    # 第三行輸出結果各元件的佈局
    self.cls_result_label.grid(row=2, column=0, rowspan=2, sticky=E)
    self.output_cls_result_list_box.grid(row=4, column=1, columnspan=10, pady=10, sticky=E)

這樣,介面就完成了。上面定義的一些元件中會有一些事件處理邏輯,比如一個按鈕Button被按下時,它就會呼叫commond屬性指定的函式。以文字分類Button為例(text_cls_button),使用者按下該按鈕後,程式就會執行garbage_name_cls函式,在該函式中我們就可以請求文字分類服務,並將返回的資料顯示到介面上。程式碼如下:

def garbage_name_cls(self):
    garbage_name = self.garbage_name_text.get()
    cat_arr = self.api_service.get_text_cls_res(garbage_name)
    self.output_cls_result_list_box.delete(0, END)

    if cat_arr:
        i = 0
        for item in cat_arr:
            name = '垃圾名稱: %s' % item.get('name', 'None')
            self.output_cls_result_list_box.insert(i, name)
            i += 1
            cat = '垃圾類別: %s' % item.get('type', 'None')
            self.output_cls_result_list_box.insert(i, cat)
            i += 1
            pre_type = '預判型別: %s' % item.get('pre_type', 'None')
            self.output_cls_result_list_box.insert(i, pre_type)
            i += 1
            tip = '投放提示: %s' % item.get('tip', 'None')
            self.output_cls_result_list_box.insert(i, tip)
            i += 1

            self.output_cls_result_list_box.insert(i, '')
            i += 1

其他事件處理邏輯類似,程式碼如下

def select_pic(self):
    """
    單選圖片
    :return:
    """
    file_name = filedialog.askopenfilename(
        filetypes=[('圖片', ('.png', '.jpg', '.jpeg'))])
    if file_name:
        self.img_name_text['state'] = NORMAL
        self.img_name_text.delete(1.0, END)
        self.img_name_text.insert(1.0, '已選擇圖片:%s' % file_name)
        self.img_name_text['state'] = DISABLED

def garbage_img_cls(self):
    img_name_text = self.img_name_text.get(1.0, END)
    if img_name_text.startswith('已選擇圖片:'):
        file_path = img_name_text[6:].strip()
    else:
        return
    with open(file_path, 'rb') as f:
        base64_data = base64.b64encode(f.read())
        img_base64 = base64_data.decode()
    cat_arr = self.api_service.get_img_cls_res(img_base64)
    self.output_cls_result_list_box.delete(0, END)

    if cat_arr:
        i = 0
        for item in cat_arr:
            name = '垃圾名稱: %s' % item.get('name', 'None')
            self.output_cls_result_list_box.insert(i, name)
            i += 1
            cat = '垃圾類別: %s' % item.get('type', 'None')
            self.output_cls_result_list_box.insert(i, cat)
            i += 1
            pre_type = '預測得分: %s' % item.get('pre_score', 'None')
            self.output_cls_result_list_box.insert(i, pre_type)
            i += 1
            tip = '投放提示: %s' % item.get('tip', 'None')
            self.output_cls_result_list_box.insert(i, tip)
            i += 1

            self.output_cls_result_list_box.insert(i, '')
            i += 1

至此,PC端桌面APP就開發完成,這裡我們沒有實現語音分類服務,但思路是一樣的,大家可以嘗試一下。小程式的程式碼我就不貼了,我會一起放到原始碼目錄中,在公眾號回覆關鍵字 垃圾分類 即可獲取整篇文章全部原始碼。今天開發這個小專案還是花了不少的時間,文章整理出來已經比較晚了,現在是凌晨1點左右,如果又不好理解的後者需要我深入講解的大家可以給我留言。另外,時間比較緊,所以APP做的比較挫,互動也比較差,有任何建議也歡迎大家留言。

歡迎公眾號「渡碼」,輸出別地兒看不到的乾貨。

相關推薦

Python快速實現一個垃圾分類APP|附帶程式

最近北京開始實行垃圾分類,導致大家對垃圾的研究熱度突然漲高,垃圾們也紛紛表示從來沒有獲得過這麼高的關注度。其實,上海市去年已經開始實行,網上已經有不少成熟的教程了,像什麼《垃圾分類從入門到精通》、《深入淺出垃圾分類》、《垃圾分類你應該掌握的10條基本原則》。這種教程如果我們親自去學顯然不符合程式設計師的個性,

APP程式的區別

自微信小程式問世以來.很多人都在問一個問題:微信小程式跟APP有什麼不同之處,其實看似簡單的問題,回答起來比較複雜,雖然兩者都屬於移動營銷,下面水滋源來具體談談微信小程式和APP區別的一些內容。 小程式: 是一種依託在微信作為平臺執行的程式也是不需要安裝即可使用的應用。實現用完即走的理念

基於uni-app程式之分包

作者:故事我忘了¢個人微信公眾號:程式猿的月光寶盒 [TOC] # 0. 緣由 ​ 最近工作在接觸uni-app,用它來開發微信小程式,也是第一次接觸,找了很久,還有大佬用自己寫的函式做的,俺覺得我不會也不配,剛好看到下面評論是官方也支援了,所以就用官方的了,這裡記錄一下 # 1. 關於分包 ​

Python 快速實現 HTTP 和 FTP 伺服器

用 Python 快速實現 HTTP 伺服器 有時你需臨時搭建一個簡單的 Web Server,但你又不想去安裝 Apache、Nginx 等這類功能較複雜的 HTTP 服務程式時。這時可以使用 Python 內建的 SimpleHTTPServer 模組快速搭建一個簡單的 HTTP 伺服器。 Si

Python socket實現一個簡單的http伺服器(post 與get 的區別)、CGIHTTPServer 簡單應用

#!/usr/bin/env python #coding=utf-8import socketimport re HOST = '' PORT = 8000#Read index.html, put into HTTP response dataindex_content = '''HTTP/1.x 200

程式什麼開發?快速開發一個自己的程式教程

一.寫在前面  1.為什麼要學小程式開發?  對於前端開發而言,微信小程式因為其簡單快速、開發成本低、使用者流量巨大等特點,也就成了前端開發工程師必會的一個技能。  2.開發準備:  (1)有人開玩笑說,會vue小程式根本都不用學:  微信小程式雖然是騰訊自己搞的,但是核心的

nodejs快速實現程式的websocket服務端

摘要: 微信小程式服務端使用websocket方式。socket.io已作為nodejs體系中被廣泛應用的websocket解決方案,卻因socket.io對websocket做了高階封裝,不能相容微信小程式所採用的websocket標準協議無法直接使用,此外微

程式(看文件寫例項十)程式課堂寶APP實現我的模組相關介面及邏輯

繼上篇博文,這篇完成最後一個模組,即我的模組。 一、頁面效果 這個模組是和使用者型別相關的,因此老師賬號和學生賬號能看的功能不一樣,老師端效果如下: 點選頭像到達個人資訊如下: 點選後可以做相應的修改。學生端的介面如下: 修改密碼的頁面如下: &nbs

程式(看文件寫例項八)程式課堂寶APP實現練習模組前臺

接上篇博文,這篇主要描述練習模組的前臺顯示,其中包括test頁面,答題detail頁面以及提交答題後答卷answer頁面。 一、練習模組test頁面 練習頁面主要展示的是當前使用者的頭像,暱稱以及學校資訊,另外還有答題資訊,以及每個章節的練習資訊,先來看看效果: grid用的是樣式

程式(看文件寫例項七)程式課堂寶APP實現線上課堂測試

接著上篇博文已經完成簽到功能,這篇來完成課堂測試功能。 一、需求描述 1、在後臺選擇題、主觀題表中上傳測試題 2、客戶端獲取題目資訊 3、把題目資訊格式化載入顯示 4、客戶端答題,主觀題每題能上傳一張答題圖片 5、客戶端答題結束提交到伺服器 二、前臺頁面 提交大量資料

程式(看文件寫例項六)程式課堂寶APP實現簽到邏輯

繼上篇博文,這篇寫下籤到實現的邏輯。 一、實現邏輯 發起簽到 1、先上傳當前自己的定位經緯度 2、學生查詢老師的最後一次簽到記錄,如果發現簽到記錄signComplete為false說明有新的簽到 3、得到簽到的第幾次課 4、系統獲得學生的定位經緯度 5、判斷兩點經緯度轉

程式(看文件寫例項五)程式課堂寶APP實現獲取簽到列表

根據上篇博文,這篇主要實現獲取簽到列表邏輯。 獲得簽到列表主要有以下步驟: (1)查詢老師的ID (2)查詢老師的簽到記錄 (3)如果當前使用者是老師,直接顯示所有記錄,因為簽到記錄都是老師發起的,肯定每次都簽到 (4)如果當前使用者是學生,以老師的簽到列表作為長度,然後以ite

程式(看文件寫例項四)程式課堂寶APP實現簽到子頁面佈局及課程視訊播放頁面

一、簽到子頁面佈局 子頁面主要是一個簽到按鈕,然後下方是簽到記錄列表。 1、簽到按鈕 佈局程式碼: <button class='sign-button' bindtap='sign'>簽到</button>

程式(看文件寫例項三)程式課堂寶APP實現整體介面框架及首頁佈局

一、首頁佈局簡單思路 回顧上一篇博文,首頁的內容主要有輪播圖,橫向滑動選單以及選單對應的view,橫向滑動選單有簽到、課堂測試、模擬測試、課堂提問、答問記錄五個選項,當點選選項時更新顯示view。由於素材和時間有限,所以佈局做得相對簡單,主要是側重思路及程式碼邏輯。 二、輪播圖 檢視文件

程式——點選商品分類跳轉到該商品的商品詳情頁面(已實現

        首先,我不得不感慨下,慕課網上“7七月”老師的課真的很強大,此處放連結https://coding.imooc.com/learn/list/75.html。        我只是學習到了一半就開

程式--video完成一個視訊彈幕的專案

1.視訊播放器 2.選擇彈幕顏色 3.彈幕來了...   第一:  index.wxml <!--index.wxml--> <view class="section tc"> <video id="myVideo" style

Python Flask構建程式訂餐系統 從專案搭建到部署上線 讓你快速掌握Python全棧開發

本課程是python flask+微信小程式完美結合,從專案搭建到騰訊雲部署上線,打造一個全棧訂餐系統。從基礎語法入手,易於掌握,構建MVC架構,增進對小程式和後端API的理解認識。深入淺出帶你進階全棧工程師課程,幫助你快速提升專案經驗,掌握專案開發技巧,提高專案中解決問題的能力。 --

Slog69_實現一個帶引數的雲函式GET!(程式之雲開發-全棧時代2)

ArthurSlog SLog-69 Year·1 Guangzhou·China Sep 11th 2018 禍兮福之所倚 福兮禍之所伏 開發環境MacOS(High Sierra 10.13.5) 需要的資訊和資訊源: 前言 騰訊推出“雲開發”概

【最佳實踐】程式客服訊息實時通知如何快速低成本實現

我們做微信小程式開發的都知道,只要在小程式頁面中新增如下程式碼即可進入小程式的客服會話介面: <button open-type="contact" >聯絡我們</button> 微信小程式客服會話介面如下圖所示:

程式~雲開發的實現一個社群 Demo(即將完結~)

微信雲開發 官方介紹 開發者可以使用雲開發開發微信小程式、小遊戲,無需搭建伺服器,即可使用雲端能力。雲開發為開發者提供完整的雲端支援,弱化後端和運維概念,無需搭建伺服器,使用平臺提供的 API 進行核