2022年2月17日 星期四

Machine learning with Raspberry Pi 4 and Coral USB Accelerator (2) -- Object Detection

 

上篇說明 Coral USB 加速器在樹梅派的安裝與使用 PyCoral 函式庫實作分類分類(Classification),但實在太久沒寫文章,上一篇文章寫得不甚好至今回頭修了好幾次,接著本篇則是實作另一個範例物件偵測(Object Detection)。

2022年2月11日 星期五

Machine learning with Raspberry Pi 4 and Coral USB Accelerator (1) -- Image Classification

因全球晶片缺貨關係,最近單板電腦(raspberry pi、nvidia jetson nano、...)不是缺貨就是漲翻天,在農曆年前有機會入手 Google coral 裝置來練一下機器學習(Machine Learning, ML),順便也在久久...未出文章的部落格留個紀錄。

2022年2月1日 星期二

MindAR: 用WebAR技術把樹藝生命之美年暦與智創虎年賀歲圖片結合在一起,虎哩幸福一整年



在這2022年的大年初一,敏哥想用WebAR技術把國立臺灣工藝研究發展中心2020年推出的樹藝生命之美年暦與智創虎年賀歲圖片結合在一起,虎哩幸福一整年,歡迎大家留意智創生活科技與樹藝工坊,將在3月份推出科技藝術種子教師培訓課程,完全是免費的喔! 

1.準備作品與

準備樹藝生命之美年暦的電子檔,可以利用手機拍照。


2.準備智創虎年賀歲圖片檔(smartcreating.jpg)。


3.利用Image Targets Compiler編譯生命之美年暦的圖片檔,轉換成影像物件檔。


把生命之美年暦的圖片檔放到上圖Drop files to upload區。


按下上圖的Start鍵


按下上圖的Download compiled鍵,下載targets.mind,並自行建立一個資料夾,例如:TreeArt。

4.從https://hiukim.github.io/mind-ar-js-doc/quick-start/webpage,取得程式碼,並儲存AR html檔案。


5.開啟Web Server for Chrome,按下"啟用應用程式"。


6.按下上圖中"CHOOSE FOLDER",選擇儲存AR.html程式的資料夾TreeArt。

7.打開Chrome瀏覽器進行測試,http://127.0.0.1:8887/AR.html。


8.修改程式,儲存成AR2.html檔案。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-image.prod.js"></script>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-image-aframe.prod.js"></script>
  </head>

  <body>
    <a-scene mindar-image="imageTargetSrc: ./targets.mind;" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
	  <a-assets>
        <img id="smartcreating" crossorigin="anonymous" src="smartcreating.jpg">
      </a-assets>
      <a-camera position="0 0 0" look-controls="enabled: false"></a-camera>
      <a-entity mindar-image-target="targetIndex: 0">
		<a-image src="#smartcreating"></a-image>
      </a-entity>
    </a-scene>
  </body>
</html>

9.把smartcreatimg.jpg檔案放到和AR.html同一個目錄下。

10.打開Chrome瀏覽器,並輸入http://127.0.0.1:8887/AR2.html,進行測試,就可以看到文章最上面圖片的景像。

2022年1月31日 星期一

MindAR: 使用Python Flask來實現WebAR

MindAR教學網站:https://hiukim.github.io/mind-ar-js-doc/face-tracking-quick-start/webpage

 Flask教學網站:https://flask.palletsprojects.com/en/2.0.x/quickstart/#a-minimal-application

1. 安裝Flask套件,開啟cmd應用程式,輸入下列命令。
pip install Flask


2.使用IDLE來編輯程式,並儲存成test.html。


3.切換到工作目錄,使用python test.py來啟動網站。


4.開啟Chrome進行測試,並輸入127.0.0.1:5000。


5.編輯face_ar.html文件,並儲存在templates資料來中,範例程式摘自Minimal Example

程式碼:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-face.prod.js"></script>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-face-aframe.prod.js"></script>
  </head>

  <body>
    <a-scene mindar-face embedded color-space="sRGB" renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
      <a-camera active="false" position="0 0 0"></a-camera>

      <a-entity mindar-face-target="anchorIndex: 1">
    <a-sphere color="green" radius="0.1"></a-sphere>
      </a-entity>
    </a-scene>
  </body>
</html>

6.改寫Flask程式-test.py,黃底是新增的部份。

1
2
3
4
5
6
7
8
from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route("/")
def hello_world(name=None):
    return render_template('face_ar.html', name=name)

7.測試時要記得在cmd中按下Ctrl+C來中止網站,再執行Python test.py命令重新啟動網站。
8.重新更新Chrome的內容,就可看到AR。


2022年1月30日 星期日

MindAR:人臉擴增實境應用

 MindAR教學文件:https://hiukim.github.io/mind-ar-js-doc/face-tracking-quick-start/webpage

AFrame教學文件:https://aframe.io/

編輯工具:Notepad++

測試工具:Web Server for Chrome

1.利用Notepad++編輯程式,範例一:Minimal Example,原始程式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-face.prod.js"></script>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-face-aframe.prod.js"></script>
  </head>

  <body>
    <a-scene mindar-face embedded color-space="sRGB" renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
      <a-camera active="false" position="0 0 0"></a-camera>

      <a-entity mindar-face-target="anchorIndex: 1">
    <a-sphere color="green" radius="0.1"></a-sphere>
      </a-entity>
    </a-scene>
  </body>
</html>

在程式的第4-6行中,分別告知MindAR臉部辨識、AFrame、以及MindAR臉部辨識與AFrame的腳本的來源。第10行中<a-scene>屬性mindar-face說明是由 MindAR 引擎來控制這個場景,第13行<a-entity> 屬性 mindar-face-target="anchorIndex: 1",說明引擎將跟踪特定的錨點位置-鼻尖。記得存成html文件,本範例為test2.html,並建立TreeArt資料夾。

2.開啟Web Server for Chrome,按下"啟用應用程式"。


3.按下上圖中"CHOOSE FOLDER",選擇儲存test2.html程式的資料夾TreeArt。

4.開啟Chrome瀏覽器,輸入http://127.0.0.1:8887/test2.html網址,就可看到一顆球在鼻尖上



5.修改anchorIndex: 1變成anchorIndex: 200,球就跑到下巴。

6. 參加AFrame文件或"好玩的WebVR,A-Fame一個針對3D/AR/VR所設計的網路框架"
,將a-sphere替換成a-box。


以下是有關臉部特點的測試:
臉部的特徵圖如下:

臉部特徵點測試:

雙人測試:


2022年1月23日 星期日

MindAR:從樹藝生命之美的卡片到設計網路版的擴增實境

 在2022年1月9日受邀參加"2022年南投縣文化資產學會第13屆第1次會員大會",這是一個很有文化內涵的學會,當天除了會員大會外,更安排國立台灣工藝研究發展中心主任張仁吉演講"台灣文化資產的價值與實踐"。


當天收到兩份很棒的工藝作品,其一是學會的藍染衣服,另一個是工藝中心的2022生命之美的年曆。





本文將介紹如何從李永謨老師創作的樹藝生命之美的卡片來實現擴增實境。
1.拍照並利用小畫家,把樹藝卡片存成圖檔。
建議您可以使用圖像分析器,來分析您圖片當成AR影像物件的品質。


2.製作AR影像目標(Image Targets Compiler),使用編譯器https://hiukim.github.io/mind-ar-js-doc/tools/compile,把上圖放在"Drop files here to upload"區,您也可以點選該區域來選擇要製AR影像目標。

選擇後

3.選擇上圖Start按鈕。

4.點選上圖"Download compiled"按鈕,儲存"targets.mind"。


把下面檔案儲存html檔,例如test.html。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-image.prod.js"></script>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-image-aframe.prod.js"></script>
  </head>

  <body>
    <a-scene mindar-image="imageTargetSrc: ./targets.mind;" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
      <a-camera position="0 0 0" look-controls="enabled: false"></a-camera>
      <a-entity mindar-image-target="targetIndex: 0">
        <a-plane color="blue" opaciy="0.5" position="0 0 0" height="0.552" width="1" rotation="0 0 0"></a-plane>
      </a-entity>
    </a-scene>
  </body>
</html>

6. 把targets.mind和test.html放在同一目錄下,例如:TreeArt。

7.執行test.html

雖然已經啟動攝像頭,但仍然無法工作,按下右鍵,選擇"檢查"按鈕。
可以發現下面問題
Fetch API cannot load file:///C:/cmlin/TreeArt/targets.mind. URL scheme "file" is not supported.

這是所謂"跨來源資源共享"的問題。

8.要解決這個問題,必須把上述兩個檔案(test.html, targets.mind)放在同一個URL中,就是網站。


就簡單方法就是安裝HFS(HTTP File Server),下載HFS伺服器執行畫面如下:

9.點選上圖Menu表單中Add files...按鈕,加入test.html和targets.mind兩個檔案。

10.打開chrome瀏覽器,輸入http://127.0.0.1/test.html,並打開攝像頭,拿著生命之美的卡片,對著攝像頭,可以展現AR。


11.另一種啟動Web伺服器的方法Web Server for Chrome

2021年12月26日 星期日

利用NFT Art Generator產生海綿寶寶的NFT圖像與JSON資料

原始程式:https://github.com/kosmosmo/NFT_Art_Generator

修訂的程式:黃底是有修訂部份,126-130行是把註解拿掉。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
project_folder = '<您的目錄>/NFT_Art_Generator-master/example/'
total_art = 100

from collections import OrderedDict
import os, json, random,cv2
import numpy as np

def create_json():
    layers_map = OrderedDict()
    my_layers = os.listdir(project_folder+'layers')
    for layer in my_layers:
        layers_map[layer] = {}
        pics = os.listdir(project_folder+'layers'+ '\\' + layer)
        temp = {'0_no_attributes':{'att_chance':1.0,'black_list_att':[]}}
        for p in pics:
            temp[p.split('.')[0]] = {'att_chance':1.0,'black_list_att':[]}
        layers_map[layer]['link_att'] = None
        layers_map[layer]['attributes'] = temp
        with open(project_folder + 'layers_map.json', 'w') as f:
            f.write(json.dumps(layers_map, indent=4, separators=(',', ': '), sort_keys=True))
    return layers_map

def get_weight(attributes):
    population = []
    weight = []
    for key,val in attributes.items():
        population.append(key)
        weight.append(val['att_chance'])
    return [population,weight]

def generate_att():
    with open(project_folder + 'layers_map.json', 'r') as f:
        layers_map = json.load(f, object_pairs_hook=OrderedDict)
    attribute_map = OrderedDict()
    visited = set()
    i = 0
    while i < total_art:
        print ('generating number ' + str(i))
        temp = OrderedDict()
        atts = ''
        for key,val in layers_map.items():
            if val['link_att'] == None:
                population, weights = get_weight(val['attributes'])
                random_pick = random.choices(population=population, weights=weights)[0]
                temp[key] = random_pick
            else:
                if temp[val['link_att']] in val['attributes']:
                    temp[key] = temp[val['link_att']]
                else:
                    temp[key] ='0_no_attributes'
            atts += key + ':' +  temp[key]+ ','
        if atts not in visited:
            visited.add(atts)
            attribute_map[i] = temp
            i += 1
    with open(project_folder + 'attributes_map.json', 'w') as f:
        f.write(json.dumps(attribute_map, indent=4, separators=(',', ': '), sort_keys=True))
    return attribute_map

def generate_art(attribute_map=None):
    if not attribute_map:
        with open(project_folder + 'attributes_map.json', 'r') as f:
            attribute_map = json.load(f, object_pairs_hook=OrderedDict)
    for key,val in attribute_map.items():
        print('generating img ' + key)
        img1 =  np.zeros((1, 1,3), dtype=np.uint8)
        for key1,val1 in val.items():
            if val1 == "0_no_attributes":continue
            img_path = project_folder + 'layers\\' +key1 + '\\' +  val1  + ".png"
            fg = cv2.imread(img_path, -1)
            fg = cv2.cvtColor(fg, cv2.COLOR_RGB2RGBA)
            fgMask = fg[:, :, 3:]
            img = fg[:, :, :-1]
            bgMask = 255 - fgMask
            imgMask = cv2.cvtColor(fgMask, cv2.COLOR_GRAY2BGR)
            bgMask = cv2.cvtColor(bgMask, cv2.COLOR_GRAY2BGR)
            bgNew = (img1 * (1 / 255.0)) * (bgMask * (1 / 255.0))
            imgNew = (img * (1 / 255.0)) * (imgMask * (1 / 255.0))
            result = np.uint8(cv2.addWeighted(bgNew, 255.0, imgNew, 255.0, 0.0))
            img1 = result
        """
        # no compression        
        cv2.imwrite(project_folder + 'outputs\\'+ key +'.png', img1)
        """
        cv2.imwrite(project_folder + 'outputs\\'+ key + '.jpg', img1, [int(cv2.IMWRITE_JPEG_QUALITY), 90])


def generate_trait_data():
    with open(project_folder + 'attributes_map.json', 'r') as f:
        attribute_map = json.load(f, object_pairs_hook=OrderedDict)
    trait_data_path = project_folder + 'outputs_data/'
    for key,val in attribute_map.items():
        res = []
        for k,v in val.items():
            if v == "0_no_attributes":continue
            att = {}
            k = '_'.join(k.split('_')[1:])
            att['trait_type'] = k
            att['value'] = v.replace('_', ' ')
            res.append(att)
        with open(trait_data_path + str(key) +'.json', 'w') as f:
            f.write(json.dumps(res, indent=4, separators=(',', ': '), sort_keys=True))


def slicing_dic(order_dic,start,end):
    list_dict = list(order_dic.items())
    slice_dic = list_dict[start:end]
    res = OrderedDict(slice_dic)
    return (res)

'''
from itertools import islice
from multiprocessing import Process
if __name__ == '__main__':
    with open(project_folder + 'attributes_map.json', 'r') as f:
        attribute_map = json.load(f, object_pairs_hook=OrderedDict)
    #attribute_map = slicing_dic(attribute_map,0,2000)  # breaking the map into smaller chunks for render.
    def chunks(data, SIZE=100):
       it = iter(data)
       for i in range(0, len(data), SIZE):
          yield {k:data[k] for k in islice(it, SIZE)}
    for item in chunks(attribute_map):
        proc = Process(target=generate_art, args=(item,))
        proc.start()
'''
create_json()
generate_att()

generate_art()
generate_trait_data()

3.因應第91行,另外還需要建立outputs_data的目錄。
4.若找不到cv2套件,可以執行pip install opencv-python
5.執行
python generator.py
6.查看結果:
圖像:

JSON資料檔:

打開0.json
[
    {
        "trait_type": "feet",
        "value": "feet"
    },
    {
        "trait_type": "cloth",
        "value": "blue pant"
    },
    {
        "trait_type": "shoe",
        "value": "dress"
    },
    {
        "trait_type": "item",
        "value": "choco"
    },
    {
        "trait_type": "hand",
        "value": "hand"
    },
    {
        "trait_type": "sleeve",
        "value": "squidward"
    },
    {
        "trait_type": "face",
        "value": "nah"
    },
    {
        "trait_type": "head",
        "value": "soda hat"
    },
    {
        "trait_type": "glasses",
        "value": "heart glasses"
    }
]