こんにちはKeita_Nakamori(´・ω・`)です。
ここから統計っぽくなってきました。
記述統計 推論統計 回帰とやっていきます。
ディレクトリの操作もJupyter notebook上でできますのでメモっています。
データの読み込み>pandas.DataFrame化
ヒストグラム 箱ひげ図 散布図
分散 標準偏差 変動係数 相関係数 共分散 相関
線形単回帰分析 決定係数(寄与率)
ローレンツ曲線 ジニ係数化
流行の科学技術を勝手に追いかけるブログ 人工知能 仮想現実 ブロックチェーン
東洋インタレスト出版
こんにちはKeita_Nakamori(´・ω・`)です。
ここから統計っぽくなってきました。
記述統計 推論統計 回帰とやっていきます。
ディレクトリの操作もJupyter notebook上でできますのでメモっています。
データの読み込み>pandas.DataFrame化
ヒストグラム 箱ひげ図 散布図
分散 標準偏差 変動係数 相関係数 共分散 相関
線形単回帰分析 決定係数(寄与率)
ローレンツ曲線 ジニ係数化
こんにちは Keita_Nakamori(´・ω・`)です。
Numpy, Scipy, pandas, Matplotlib, seaborn の基礎です。
この章も、Python慣れしている方は読み飛ばして問題ない章です。
スクリプトメモ
こんにちは、Keita_Nakamori(´・ω・`)です。
「東京大学のデータサイエンティスト育成講座」を参考に学習を進めています。
pythonで色々と実行していきますので、章ごとにスクリプトのメモを残していこうと思います。※ 我流でやっていますので本書の中身とは異なります。
第一章はpythonの基礎的な操作方法なので、なれている方にとっては読み飛ばして良いところです。
無名関数(ラムダ式)の復習くらいですかね。ああ、そんなのもあったな程度です。高階関数 イテレーター ジェネレータ デコレーターなどは出てきません。
基本、なくてもデータサイエンスでは困りません。
スクリプトメモ
やっていきましょう (´・ω・`)これで一旦終わりにします。
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 |
from django.shortcuts import render from django.shortcuts import redirect # 追加 # Httpレスポンスをするためのモジュール from django.http import HttpResponse # テンプレートファイルを読み込む from django.template import loader # forms.pyで定義したPhotoFormクラスを呼び出す from .forms import PhotoForm # models.pyで定義したPhotoクラスを呼び出す from .models import Photo #追加 def index(request): # webサイトのindex.html に相当する部分 # 構造がとても複雑だが、こういうものだと諦めること。 # 引数としてrequestを受け取る # index.htmlを読み込み # オブジェクトtemplateを定義する template = loader.get_template('carbike/index.html') #追加 # forms.pyのクラスPhotoFormのインスタンスを作成して、 # ディクショナリcontextを定義しておく。 context = {'form':PhotoForm()} # オブジェクトtemplateのrender関数に # フォームcontextと引数requestを入れて # HttpResponseを返す return HttpResponse(template.render(context, request)) def predict(request): # POSTでなければindexへ強制遷移します。 if not request.method =='POST': # return なにも返さない print("redirect('carbike:index')が動きます") redirect('carbike:index') # < これ以降はPOSTでデータが取得できている状態 > # PhotoFormインスタンスを作成する form = PhotoForm(request.POST, request.FILES) # 念の為、データが空だったらエラーを返す if not form.is_valid(): raise ValueError('Formが不正です') # 変数Photo に 画像データを格納する。 # (別途Photoクラスを作成する必要がある。models.py参照) photo = Photo(image=form.cleaned_data['image']) print("変数photoにPhoto(image=form.cleaned_data['image'])を格納完了") print(photo) # 判断結果のリターンをmodels.pyのpredictメソドから取得する predicted, percentage = photo.predict() # 表示する内容 template = loader.get_template('carbike/result.html') context = { 'photo_name': photo.image.name, 'photo_data': photo.image_src(), 'predicted': predicted, 'percentage': percentage, } return HttpResponse(template.render(context, request)) |
1 2 3 4 5 6 |
# フォームを生成するモジュール from django import forms class PhotoForm(forms.Form): # 画像をアップロードする機能 image = forms.ImageField(widget=forms.FileInput(attrs={'class':'custom-file-input'})) |
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 |
from django.db import models # Create your models here. import numpy as np #tfよりも先に行っておく # 追加モジュール import io, base64 #画像ファイルを数値に変換 ブラウザへ画像を戻す import tensorflow as tf #追加 # vgg16_predict.pyからモジュールをコピペ import numpy as np from PIL import Image import sys from tensorflow import keras from tensorflow.keras.models import load_model # 推論するセッションの初期化を行っておく graph = tf.get_default_graph() class Photo(models.Model): # models.Modelを拡張してPhotoクラスを作成する # 画像データをアップロードするディレクトリを指定する # myproject直下に /media/photos の2階層ディレクトリを新規作成すこと。 image = models.ImageField(upload_to='photos') # < vgg16 パラメータ > # 画像サイズ IMAGE_SIZE = 224 # モデルファイルを読み込む(別途フォルダ作成が必要) # ./car_motorbike/ml_models/vgg16_trans.h5 を作成しておくこと。 MODEL_FILE_PATH = './car_motorbike/ml_models/vgg16_trans.h5' print('モデルファイルパス読み込み完了') # vgg16_predict.pyからコピペ # 出力結果のクラスを定義 classes = ["car", "motorbike"] num_classes = len(classes) # クラス数を定義 def predict(self): print('Photo.predictメソド開始') # 引数から画像ファイルを参照して読み込む # クラスメソドとして定義してあげる # モデルの初期化 model = None # 毎回同じモデルのセッションにデータを投入するためグローバル変数とする global graph with graph.as_default(): # 予め定義しておいたMODEL_FILE_PATH からモデルを定義できるようにする model = load_model(self.MODEL_FILE_PATH) # 画像データを格納する img_data = self.image.read() # 画像データをメモリ上に保持して、ファイルのようにアクセスできるよう、 # バイナリデータに変換する img_bin = io.BytesIO(img_data) # pillow の Imageでバイナリデータを開く image = Image.open(img_bin) # 以下、vgg16_predict.pyからコピペ # 画像サイズを定義(VGG16に合うように) # image_size = 224 クラスとして定義済み # 画像ファイルをコマンドラインの第2引数から開く # 今回はimag_binから開くので不要 # image = Image.open(sys.argv[1]) # 画像ファイルをRGBに変換する image = image.convert('RGB') # 画像を同じサイズに揃える # image = image.resize((image_size, image_size)) image = image.resize((self.IMAGE_SIZE, self.IMAGE_SIZE)) # RGB値をnumpy配列に変換する data = np.asarray(image) # データを正規化する data = data / 255.0 # リストにappendしてnumpy配列にする X = [] X.append(data) X = np.array(X) # VGG16_transモデルをロードする # model = load_model('./vgg16_trans.h5') すでに上記で行っているので不要 # VGG16_transモデルにデータを入れて予測結果を返す # スコアが配列で帰ってくるので[0]番目をつける result = model.predict([X])[0] # 最も大きい数字を採用する predicted = result.argmax() percentage = int(result[predicted] * 100) # プリントする print(self.classes[predicted], percentage) # 判断結果とパーセンテージをreturnする return self.classes[predicted], percentage def image_src(self): # views.pyの 'photo_data': photo.image.src() へ連動させる with self.image.open() as img: base64_img = base64.b64encode(img.read()).decode() return 'data:' + img.file.content_type + ';base64,' + base64_img |
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 |
<!-- リザルトページを作成します。--> <!-- テンプレートであるbase.htmlに対して 拡張する宣言をします。--> {% extends 'carbike/base.html' %} <!-- タイトル title をbase.htmlに埋め込みます。--> {% block title %}判定結果{% endblock %} <!-- 内容 content をbase.htmlに埋め込みます。--> {% block content %} <div> <!-- classはbootstrap記法で文字間の調整になる mtマージントップ mb マージンボトム 境界線底部 --> <h4 class="mt-4 mb-5 border-bottom">車とバイクを判別します。</h4> <!-- 判別結果と推定確率のテーブルを設置する --> <table class='table'> <tbody> <tr> <td>ファイル名</td> <td>{{ photo_name }}</td> </tr> <tr> <td>画像ファイル</td> <td><img class='preview-img' src={{ photo_data }}></img></td> </tr> <tr> <td>推定ラベル</td> <td>{{ predicted }} </td> </tr> <tr> <td>推定確率</td> <td>{{ percentage }} %</td> </tr> </tbody> </table> <!-- 戻るボタンを設置する --> <a href="{% url 'carbike:index' %}" class="btn btn-primary">画像選択メニューに戻る</a> </div> {% endblock %} |
conda activate djangoai
cd anaconda_projects
cd djangoai
cd myproject
pythin manage.py runserver
url:http://127.0.0.1:8000/carbike
いやー疲れました、djangoは難しい。小さなアプリでも多くのファイル間を連携させないと動いてくれないんですね。
今後は、マッチングアプリや遠隔監視カメラなんてものを作ってみたいと思います。
前回は、数値の出力まででしたので、今回はリアルタイムプロットに挑戦します。
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 |
# -*- coding: utf-8 -*- import smbus import math from time import sleep from time import perf_counter import time import matplotlib.pyplot as plt #mpu6050のデバイスアドレス(決まっている) DEV_ADDR = 0x68 ACCEL_XOUT = 0x3b ACCEL_YOUT = 0x3d ACCEL_ZOUT = 0x3f TEMP_OUT = 0x41 GYRO_XOUT = 0x43 GYRO_YOUT = 0x45 GYRO_ZOUT = 0x47 PWR_MGMT_1 = 0x6b PWR_MGMT_2 = 0x6c # sudo i2cdetect 0 : Error: Could not open file `/dev/i2c-0' or `/dev/i2c/0' # sudo i2cdetect 1 : I will probe file /dev/i2c-1 # エラーの出ない方がバス番号(0 か 1) # コネクションオブジェクトを取得 bus = smbus.SMBus(1) # write_byte_data(アドレス, コマンド, 1バイトの値) # スリープを解除 多分(最初はスリープしている) bus.write_byte_data(DEV_ADDR, PWR_MGMT_1, 0) # make plot times = [0 for i in range(60)] axs = [0 for i in range(60)] time = 0 ax = 0 # initialize matplotlib plt.ion() plt.figure() li_x, = plt.plot(times, axs) # need " , " #li_y, = plt.plot(times, ays) # need " , " #li_z, = plt.plot(times, azs) # need " , " #plt.xlim(-1,1) plt.ylim(-2,2) plt.xlabel("time") plt.ylabel("ax,ay,az") plt.title("ax,ay,az real time plot") def read_word(adr): high = bus.read_byte_data(DEV_ADDR, adr) low = bus.read_byte_data(DEV_ADDR, adr+1) val = (high << 8) + low return val def read_word_sensor(adr): #2バイトデータから 1ワードデータへデコードする val = read_word(adr) if (val >= 0x8000): return -((65535 - val) + 1) else: return val def get_temp(): # 温度を算出する temp = read_word_sensor(TEMP_OUT) x = temp / 340 + 36.53 # data sheet(register map)記載の計算式. return x def getGyro(): # 3軸 角速度を算出する x = read_word_sensor(GYRO_XOUT)/ 131.0 y = read_word_sensor(GYRO_YOUT)/ 131.0 z = read_word_sensor(GYRO_ZOUT)/ 131.0 return [x, y, z] def getAccel(): # 3軸 加速度を算出する x = read_word_sensor(ACCEL_XOUT)/ 16384.0 y= read_word_sensor(ACCEL_YOUT)/ 16384.0 z= read_word_sensor(ACCEL_ZOUT)/ 16384.0 return [x, y, z] # Define initial time t_init = perf_counter() while perf_counter() - t_init < 60.0 : t = perf_counter() - t_init # 3軸 加速度を算出し出力する ax, ay, az = getAccel() print ('{0:4.3f}, {1:4.3f}, {2:4.3f}, {3:4.3f}' .format(t, ax, ay, az)) #最新のデータを追加すると同時に最初のデータを削除する times.append(t) times.pop(0) axs.append(ax) axs.pop(0) #ays.append(ax) #ays.pop(0) #azs.append(ax) #azs.pop(0) # 区間プロットする li_x.set_xdata(times) li_x.set_ydata(axs) plt.xlim(min(times), max(times)) plt.draw() # plt.ion()に対応 (plt.show()ではない) plt.pause(0.01) sleep(0.02) |
できました! 以上です。
こんにちは、加速度センサーのMPU-6050を買ったので、試運転してみます。
使用するピンは 1 , 3 , 5 , 6 です。
MPU-6050の電源電圧は 3.3[V] ですが、GY-521に3.3[V]のレギュレータICが載っていて、I2Cバスのプルアップ抵抗が 3.3[V] へ繋がっているので、5[V]電源の Arduino に直接つないで使うことが出来ます。
という記述を見つけましたが、おとなしく+3.3Vに接続します。
ラズパイの設定でSSH,VNC,I2C,SPIとか全部 有効にします。
ターミナルで >ifconfigして アドレスを確認します。
192.168.10.xxx
ウィンドウズマシン上でVNC Viewerから新規コネクト作成で192.168.10.114します。
このとき、重要なのは ユーザーネームは自分で設定したIDではなくて pi です!!で、パスワードは自分で設定したやつです。
非常に紛らわしいですね。毎回詰まります。
$ gpio readall
すると、GPIOの一覧が確認できます。
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 |
+-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | | | 3.3v | | | 1 || 2 | | | 5v | | | | 2 | 8 | SDA.1 | ALT0 | 1 | 3 || 4 | | | 5v | | | | 3 | 9 | SCL.1 | ALT0 | 1 | 5 || 6 | | | 0v | | | | 4 | 7 | GPIO. 7 | IN | 0 | 7 || 8 | 1 | ALT5 | TxD | 15 | 14 | | | | 0v | | | 9 || 10 | 1 | ALT5 | RxD | 16 | 15 | | 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 | | 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | | | 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 | | | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 | | 10 | 12 | MOSI | ALT0 | 0 | 19 || 20 | | | 0v | | | | 9 | 13 | MISO | ALT0 | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 | | 11 | 14 | SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT | CE0 | 10 | 8 | | | | 0v | | | 25 || 26 | 1 | OUT | CE1 | 11 | 7 | | 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 | | 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | | | 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 | | 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | | | 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 | | 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 | | | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+ |
$ sudo i2cdetect -y 1
すると、I2Cが接続されているのが確認できます。
1 2 3 4 5 6 7 8 9 |
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- |
では、加速度を取得してみましょう。ベタ貼りしてみました。
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 |
# -*- coding: utf-8 -*- import smbus import math from time import sleep import time DEV_ADDR = 0x68 ACCEL_XOUT = 0x3b ACCEL_YOUT = 0x3d ACCEL_ZOUT = 0x3f TEMP_OUT = 0x41 GYRO_XOUT = 0x43 GYRO_YOUT = 0x45 GYRO_ZOUT = 0x47 PWR_MGMT_1 = 0x6b PWR_MGMT_2 = 0x6c bus = smbus.SMBus(1) bus.write_byte_data(DEV_ADDR, PWR_MGMT_1, 0) def read_word(adr): high = bus.read_byte_data(DEV_ADDR, adr) low = bus.read_byte_data(DEV_ADDR, adr+1) val = (high << 8) + low return val def read_word_sensor(adr): val = read_word(adr) if (val >= 0x8000): return -((65535 - val) + 1) else: return val def get_temp(): temp = read_word_sensor(TEMP_OUT) x = temp / 340 + 36.53 # data sheet(register map)記載の計算式. return x def getGyro(): x = read_word_sensor(GYRO_XOUT)/ 131.0 y = read_word_sensor(GYRO_YOUT)/ 131.0 z = read_word_sensor(GYRO_ZOUT)/ 131.0 return [x, y, z] def getAccel(): x = read_word_sensor(ACCEL_XOUT)/ 16384.0 y= read_word_sensor(ACCEL_YOUT)/ 16384.0 z= read_word_sensor(ACCEL_ZOUT)/ 16384.0 return [x, y, z] while 1: ax, ay, az = getAccel() gx, gy, gz = getGyro() print ('{0:4.3f},{0:4.3f},{0:4.3f},{0:4.3f},{0:4.3f},{0:4.3f},' .format(gx, gy, gz, ax, ay, az)) |
ちゃんと動いていますね。
数値データをグラフ化して見ましょう。
動的にmatplotlibを利用する必要がありますので、ちょっと考えなくてはなりません。
こんにちは Keita_Nakamoriです。(´・ω・)
台風19号が接近し、レベル4の避難命令が出ましたので最寄りの小学校へ避難しております。ひまです。
無名関数を使うときはlambda(ラムダ)と書きます。
def xxx(a, b): に相当します。
通常の関数で言うところの return a*b に相当します。
xxx関数を定義したとして、xxx(5,8) のように引数を2つ渡すことに相当します。
以上より、通常の関数では
1 2 3 4 |
def xxx(a,b): return a*b xxx(5,8) |
のところを
一行で (lambda a,b : a*b)(5,8)
と書けるのです。
書いているうちに台風が去っていきました。お家に帰りましょう。(´・ω・)
前回までで carbikeのindex画面とpredict画面を生成しました。
今回はhtmlを記述していってwebサイトをかっこよくしていきます。
django-bootstrap4を使いますので、
> pip install django-bootstrap4をします。
django-bootstrap4-1.0.1 が入りました。
/myproject/car_motorbike/ の下に
というファイルを3つ作成します。
まずはじめに各ページ共通の部分である雛形としてbase.htmlを作成します。
index.htmlとpredict.htmlには各ページ固有の内容を記述して、雛形であるbase.htmlに埋め込んでいくやり方を取ります。
各ページ共通の部分である雛形です。
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 |
<!DOCTYPE html> <!-- この base.html はテンプレートファイルとして作成され、各ページに流用されます。 --> <html lang="ja"> <head> <meta charset="UTF-8"> <!-- static/carbike/css/style.cssを参照できるようにディレクトリを指定する--> {% load static %} <!-- django-bootstrap4 と bootstrap_cssを使用する宣言--> {% load bootstrap4 %} {% bootstrap_css%} <!-- ディレクトリstaticの下のcarbike/css/style.cssを読み込む --> <link rel='stylesheet' type="text/css" href="{% static 'carbike/css/style.css' %}"> <!-- bootstarap_javascript の jquery を読み込む --> {% bootstrap_javascript jquery='full' %} <!-- 各ページ固有のタイトル title を代入する部分 --> <title>Image classification by TensorFlow | {% block title %}{% endblock %}</title> </head> <body> <!-- ナビゲーションバーを設置する --> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navber-brand" href="#">Image classification by TensorFlow</a> </nav> <!-- メインの内容を設置する --> <div class="container"> <!-- 各ページの内容 content を代入する部分 --> {% block content%}{% endblock %} </div> </body> </html> |
bootstrap4の記法は下記のようにDTL: Django Template Languageで
{% xxxxxxx %} と書きます。
{% block title %}{% endblock %} の部分にindex.html,およびpredict.html各ページ固有のタイトルが代入されます。
{% block content%}{% endblock %} の部分にindex.html,およびpredict.html各ページ固有の内容が代入されます。
上記、base.htmlの中で、スタイルシートの宣言をしていますが、自分でディレクトリとファイルを作成する必要があります。
<link rel=’stylesheet’ type=”text/css” href=”{% static ‘carbike/css/style.css’ %}”>
staticディレクトリを myproject/car_motorbike/直下(templatesと同階層に作成して、その中に/carbike/css/style.css というcssファイルを作成しておきます。
あとで記述していきますので、現時点では空ファイルでOKです。
indexベージを作成します。
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 |
<!-- インデックスページを作成します。--> <!-- テンプレートであるbase.htmlに対して 拡張する宣言をします。--> {% extends 'carbike/base.html' %} <!-- タイトル title をbase.htmlに埋め込みます。--> {% block title %}車とバイクの画像をTensorFlowで判別するdjangoアプリ{% endblock %} <!-- 内容 content をbase.htmlに埋め込みます。--> {% block content %} <div> <!-- classはbootstrap記法で文字間の調整になる mtマージントップ mb マージンボトム 境界線底部 --> <h4 class="mt-4 mb-5 border-bottom">車とバイクを判別します。</h4> <p>画像ファイルを選択して ボタンをクリックしてください。</p> <!-- ファイルの投稿フォームを作成 実行したときのページ移動先の指定 ファイル送付方式 クラス名定義 エンコードタイプ指定--> <form action="{% url 'carbike:predict' %}" method="post" class="form" enctype="multipart/form-data"> <!-- サーフ対策:外部プログラムからデータを送りつけられないようにする--> <!-- cross site request forgery 対策--> {% csrf_token %} <!-- データのアップロードフォームを作成する --> <div class="form-group"> <div class="custom-file"> <!-- 二重括弧の意味 ==> djandoの変数を参照する--> <!-- form.image ==>views.pyから送られてくる imageの値を取得してformに埋め込む--> {{ form.image }} <label class="custom-file-label" for="customFile"> ここをクリックしてください。 </label> </div> </div> <!-- submitボタンを設置する --> <button type="submit" class="btn btn-primaty">提出</button> </form> </div> {% endblock %} |
雛形ページであるbase.htmlに対してタイトルと拡張宣言をします。
{% extends ‘carbike/base.html’ %}
{% block title %}xxxx{% endblock %}
{% block content %}xxxx{% endblock %}
myproject/car_motorbike/の下に forms.pyを新規作成します。
1 2 3 4 5 6 |
# フォームを生成するモジュール from django import forms class PhotoForm(forms.Form): # 画像をアップロードする機能 image = forms.ImageField(widget=forms.FileInput(attrs={'class':'custom-file-input'})) |
indexページの表示内容であるindex関数の部分を hello worldをreturnするだけの状態から、formを表示する内容に変更します。
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 |
from django.shortcuts import render # Httpレスポンスをするためのモジュール from django.http import HttpResponse # テンプレートファイルを読み込む from django.template import loader #追加 # forms.pyで定義したPhotoFormクラスを呼び出す from .forms import PhotoForm #追加 # models.pyで定義したPhotoクラスを呼び出す # まだ作っていないので保留 # from .models import Photo #追加 def index(request): # webサイトのindex.html に相当する部分 # 構造がとても複雑だが、こういうものだと諦めること。 # 引数としてrequestを受け取る # index.htmlを読み込み # オブジェクトtemplateを定義する template = loader.get_template('carbike/index.html') #追加 # forms.pyのクラスPhotoFormのインスタンスを作成して、 # ディクショナリcontextを定義しておく。 context = {'form':PhotoForm()} # オブジェクトtemplateのrender関数に # フォームcontextと引数requestを入れて # HttpResponseを返す return HttpResponse(template.render(context, request)) def predict(request): # 仮のリターンを作っておく return HttpResponse('show predictions here') |
やっていることは3つのみ
1.テンプレートオブジェクトを定義
template = loader.get_template(‘carbike/index.html’)
2.コンテキストオブジェクトを定義
context = {‘form’:PhotoForm()}
3.HttpResponseをreturnする
return HttpResponse(template.render(context, request))
現在このアプリケーションが認識されているアプリ名を確認します。
CarMotorbikeConfigクラスの中に name = ‘car_motorbike’ と定義されています。
1 2 3 4 5 |
from django.apps import AppConfig class CarMotorbikeConfig(AppConfig): name = 'car_motorbike' |
これを 後述のsettings.pyのINSTALLED_APPSリストに追加します。
リストINSTALLED_APPS にクラス名’car_mortorbike.apps.CarbikeConfig’と ‘bootstrap4’を追記します。
1 2 3 4 5 6 7 8 9 10 11 12 |
# Application definition INSTALLED_APPS = [ 'car_motorbike.apps.CarMotorbikeConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'bootstrap4', ] |
仮想環境へ conda activate djangoai
開発サーバーへ python manage.py runserver
url http://127.0.0.1:8000/carbike
ここで、画像を選択肢画提出ボタンを押すと、ページが遷移します。
ここはまだ作り込んでいないので、これでOKです。
以上、次回は第11回目です。
django 複雑ですねえ。これは習得するのに時間がかかる・・・。(´・ω・`)
前回、myproject管理フォルダ内のurls.pyを編集しましたが、今回は
car_motorbikeアプリケーションフォルダ直下に、同じくurls.pyを新規作成して、下記スクリプトを書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from django.urls import path # 追加モジュール 今回は同じ階層にある # さらにアプリケーションと同じ階層(.)なので viewsは被らない。 # よって、基本構文で良い from . import views app_name = 'carbike' # 追加した # urlパターンをリストで作っておく urlpatterns = [ path('', views.index, name='index'), # predictアドレス 後ほどviewsにpredictメソドを定義するために # views.py へ def predict(): を追加する path('predict/', views.predict, name='predict'), ] |
1.当該スクリプトで使用するモジュールであるviews.py は 当該urls.pyと同層になるので
from . import views
という不思議なインポート記述になります。
viewsモジュールはまだ作成していませんので実行すると当然エラーになりますが、あとで作成しますので心配いりません。
2.そして、画像を入力したときにvvc16_predct.pyを走らせて予測結果を返す画面である predict画面を定義します。
urlpatternsリストにリスト要素として
path(‘predict/’, views.predict, name=’predict’)
を追加します。これで urlのツリー構造として /carbike/predict が定義されたことになります。
views.predictメソドはこれから作成しなければなりませんので、現時点ではエラーが出ます。
3.なお、このcar_motorbike/urls.pyスクリプトは myproject/urls.py から呼び出されるものなので、これから myproject/urls.py の方を改良していきます。
ルーティングというやつです。
ではここから car_motorbike/urls.py へルートをつなげていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from django.contrib import admin # includeメソドを追加で読み込む from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # 追加urlパターン carbikeというフォルダを見に来たら、carbike.indexを呼び出す # path('carbike/', carbike.index), # 追加urlパターン carbikeというフォルダを見に来たら、 # car_motorbike.urls.pyの中にあるルーティングを読みに行く path('carbike/', include('car_motorbike.urls')), ] |
1.include関数を新たにインポートして 、先程作成した car_mortorbike/urls.pyを参照するようリストurlpatternsにリスト要素としてpath(‘carbike/’, include(‘car_motorbike.urls’))を追加します。
2.これで、ブラウザ上のurl指定に/carbikeが追加されたとき、car_motorbike.urlsスクリプトを見に行くことになります。
先程、car_motorbike/urls.py 内で views.predictメソドを記述しましたが、それの実体をここで定義します。とりあえずルーティングが正しく行われて表示されるか確認したいので、実行内容としてはテキストを出力するだけの最低限にしてテストしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from django.shortcuts import render # 追加モジュール from django.http import HttpResponse def index(request): # webサイトのindex.html に相当する部分 # 仮のリターンを作っておく return HttpResponse('hello_world') def predict(request): # webサイトのpredict.html に相当する部分 # 仮のリターンを作っておく return HttpResponse('show predictions here') |
では python manage.py runserver して ブラウザで動作チェックをしましょう。
1.http://127.0.0.1:8000/ を入力すると
>[21/Sep/2019 15:53:08] “GET / HTTP/1.1” 404 2032
トップページは作っていませんから、404エラーで問題ありません。
2.http://127.0.0.1:8000/carbike を入力すると
>[21/Sep/2019 15:53:17] “GET /carbike/ HTTP/1.1” 200 11
200と出ていますのでちゃんと認識しています。
3.http://127.0.0.1:8000/carbike/predict
>[21/Sep/2019 15:53:30] “GET /carbike/predict/ HTTP/1.1” 200 21
と 200が帰ってくるのでこちらも正常に動作しています。
Web Application: 第10回 HTMLでかっこよくする