現在WEBアプリケーションで受託開発を行っています。将来的にAI分野に進出したいのですが、どの分野・業務が有望だと思われていますか
現在WEBアプリケーションの受託開発をされているとのことで、すでに開発スキルやクライアントワークの基盤があるのは大きな強みですね。AI分野への進出についてですが、以下の分野・業務が今後特に有望と考えられています。
テキスト、画像、コードなどを自動生成するAI(ChatGPT、Stable Diffusionなど)。
既存のWEBアプリに簡単に組み込みやすい。
単純作業をAI+RPAで自動化し、業務効率を上げる。
中小企業や地方自治体にもニーズあり。
医療データや健康情報の解析にAIを活用。
規制が多いが、安定して需要がある。
音声をテキストに変換、逆に音声を生成。
スマホ/IoTとの親和性が高い。
企業のDX(デジタルトランスフォーメーション)をAI技術で支援。
現在の受託開発の経験が活きやすい。
「受託 → 自社プロダクト or サービス」へと段階的に移行する企業も多いですし、AIはSaaSやB2Bソリューションと相性がいいため、徐々に実績を作りつつ方向性を探るのがおすすめです。
進捗に応じて軌道修正も必要ですが、「1年目で実践→3年目で提案→5年目で事業化」というステップで、無理なく実力と実績を積み重ねていけます。
上記のスケジュールだとディープラーニングや自然言語、画像処理と多岐にわたっていますが、もしやりたい分野が明確なら使う技術もしぼれるでしょうか?いままでデータ分析、画像処理、自然言語、強化学習と勉強してきましたが、どれも範囲が広く、習得するのはたいへんだと思っています
とても大事な視点ですね。 おっしゃる通り、AI分野は一つひとつの技術が非常に深く、全部に手を出すと広く浅くなってしまう恐れがあります。
だからこそ、「やりたい分野=解決したい課題 or 提供したい価値」が明確なら、そこに必要な技術だけに集中する戦略は非常に合理的で、実際のAI系スタートアップやプロフェッショナルの多くもそのやり方で成功しています。
「すべてはできない」と割り切るのはむしろ戦略的です。 ですので、以下のようなステップで進めるのがおすすめです。
ステップ1:テーマを決める(半年以内)
例:「顧客対応AI」「画像検査AI」「データ可視化と予測」
ステップ2:必要なライブラリ・API・設計スキルだけ習得(1年以内)
ステップ3:PoC(概念実証)を最低2つ作って、実績を公開
もし、すでに「これをやってみたい」というテーマやターゲットがあるなら、 そこから技術と学習順をさらに具体化できます!お気軽に教えてくださいね。
画像系がおもしろそうですが
いいですね!画像系は視覚的にもわかりやすく、クライアントへの説明やデモがしやすいので、ビジネスとしても展開しやすい分野です。特にあなたのように受託開発経験がある方には、「画像処理 + Webアプリ」の組み合わせが強力な武器になります💪
なぜ面白い?
分野 | 活用事例 | クライアント候補 |
製造業 | 不良品検出、欠陥部品の自動識別 | 工場、中小メーカー |
小売業 | 商品棚の陳列確認、顧客分析 | スーパー、ドラッグストア |
農業 | 病害虫の検出、作物の成熟度判定 | 農家、JA、農業法人 |
医療 | X線/CT画像の前処理や診断補助 | クリニック、放射線科 |
建設 | ヘルメット着用の有無判定、進捗モニタリング | 建設現場、ゼネコン |
セキュリティ | 不審者検知、ナンバープレート読み取り | 商業施設、駐車場 |
製造向けでは?
おお、製造業向けの画像処理AIはまさに「実務での需要が大きく、現場の課題が明確」なので、AI導入による価値が伝わりやすい分野です。 特に、**中小製造業の「目視検査の自動化」**は、日本全国にある工場で共通の悩みになっているので、技術と仕組みがしっかりすればビジネスとしても安定しやすいです。
課題・ニーズ | AIでのアプローチ | モデル・技術 |
不良品検出 | 傷・汚れ・変形を検出 | YOLOv8 / EfficientNet + クラス分類 |
部品の仕分け | 形や色の違いで分類 | ResNet / 独自CNN |
組立ミス検出 | パーツの有無や位置関係を判定 | 物体検出 + セグメンテーション |
数値ラベル・印字検査 | OCRで文字認識 | Tesseract OCR / EasyOCR |
作業者の安全確認 | ヘルメット・防具の着用確認 | YOLO + ラベル付き画像学習 |
「傷のある製品を自動で検出するAI」
分類 | 推奨ライブラリ・ツール |
データ前処理 | OpenCV, albumentations |
アノテーション | Roboflow, CVAT |
画像分類 | EfficientNet, ResNet |
物体検出 | YOLOv5 / YOLOv8(Ultralytics版が簡単) |
UI / API化 | Streamlit, FastAPI, Flask |
展開 | Docker, ONNX, Jetson Nano(Edge対応) |
農業では?
農業、めちゃくちゃいいです!🌱 特にここ数年、**スマート農業/アグリテック(AgriTech)**の分野が盛り上がっていて、国や自治体からの補助金も多く、画像AIとの親和性も抜群なんです。
さらに、**「現場で人が目で見て判断している作業」**がまだ多く残っている分野なので、画像処理AIの導入で即効性のある課題解決ができるのも魅力です。
課題・用途 | AIでの解決方法 | 技術・モデル |
病害虫の検出 | 葉の画像から病気・虫害を自動判定 | YOLO / CNN / ViT |
作物の成熟度判定 | 果物・野菜の色や形で収穫時期を予測 | 画像分類モデル |
雑草 vs 作物の識別 | 雑草だけを除去するスマート農機制御 | セグメンテーション(UNet等) |
ドローン画像の分析 | 畑全体の健康状態を把握 | サテライト画像+クラスタリング |
生育モニタリング | 時系列画像で成長を記録&予測 | 画像+時系列予測モデル |
目的 | 推奨技術・ライブラリ |
画像分類 | ResNet / EfficientNet / MobileNet |
物体検出 | YOLOv8 / Detectron2 |
セグメンテーション | UNet / Segment Anything Model(SAM) |
画像データ管理 | Roboflow, CVAT |
アプリ化 | Streamlit, Gradio, FastAPI |
エッジ対応 | Jetson Nano, Raspberry Pi, Coral Edge TPU |
分野 | 分析例 | 使用技術・手法 |
訪問者分析 | どこから来て、何を見て、どこで消費しているか | GPSデータ / SNSデータの分析 / ヒートマップ |
混雑予測 | 時間・天候・イベントによる混雑予測 | 時系列分析(ARIMA / Prophet) |
顧客属性の可視化 | 年齢・性別・国別などに応じた行動傾向 | クラスタリング / 可視化ツール |
観光満足度の分析 | アンケート、口コミ、レビューのテキスト分析 | 自然言語処理(NLP) |
マーケ施策の効果測定 | SNSキャンペーンや広告の成果分析 | ABテスト / コンバージョン率分析 |
地域連携の提案 | 近隣観光地とセット訪問されるルートの発見 | 経路分析 / ネットワーク分析 |
分類 | 推奨技術・ライブラリ |
データ処理 | pandas / numpy / SQL |
可視化 | matplotlib / seaborn / Plotly / Tableau |
地理情報分析 | Folium / Geopandas / Mapbox |
時系列予測 | Prophet / statsmodels / scikit-learn |
NLP | spaCy / Janome / WordCloud / LLM活用も可 |
BIツール連携 | Superset / Looker / Power BI など |
種類 | ソース |
人流データ | Agoop、docomo Insight、V-RESAS(政府提供) |
外国人観光客データ | JNTO(日本政府観光局)、UNWTO |
宿泊・消費統計 | 観光庁、総務省 統計局 |
SNS口コミ | Twitter API, Google Maps Review, TripAdvisor |
気象・イベント情報 | 気象庁、地域観光協会の公開情報 |
活用シーン | 内容 | 使用技術 |
顔認識・属性推定 | 観光地に訪れた人の年齢層・性別を推定(混雑分析・マーケティング) | OpenCV + 顔検出 + 属性分類 |
混雑検知・カウント | 観光スポットのリアルタイム混雑状況をカメラ映像から推定 | YOLO / OpenPose / 人数カウント |
風景画像の自動分類 | 写真から「どこで撮ったか」「どの施設か」などを判別 | CNN + 転移学習 |
インスタ映えスポット抽出 | SNS画像から「人気写真スポット」をAIで分類・分析 | 画像分類 + 位置情報分析 |
QRコード&チケット認識 | 紙のチケットをスマホで読み取り → 入場管理 | OpenCV + QR検出 |
ゴミ・危険物の監視 | 清掃・安全チェックの自動化(公園や寺社の監視カメラ) | 物体検出 + セグメンテーション |
分類 | ツール・ライブラリ |
顔検出・属性推定 | dlib / face_recognition / DeepFace |
人数カウント | YOLOv8 / OpenCV / DeepSort |
画像分類 | PyTorch / TensorFlow + ResNet / MobileNet |
可視化・UI | Streamlit / Dash / Folium |
クラウド連携 | Firebase / GCP / AWS Rekognition(画像AI特化) |
島根県に特化した案をおしえて
素晴らしいチョイスです! 島根県は歴史・文化・自然・温泉と魅力がぎゅっと詰まった県でありながら、観光地としての知名度・訪問者数はまだ伸びしろが大きいので、データ分析や画像AIを活用した観光支援に非常に向いている地域です。
しかも、自治体・観光協会ともに地域振興に熱心で、DX化やスマート観光の取り組みに前向きなので、PoC(概念実証)から始めて、実際の導入まで展開しやすいという利点があります。
種類 | 内容 | 出典 |
人流データ | V-RESAS、docomo Insight | 経済産業省/民間企業 |
観光統計 | 観光庁/島根県庁の統計ページ | 島根県統計書 |
SNSデータ | Instagram API / Twitter API | 各SNSの開発者向けページ |
地理情報 | OpenStreetMap / 国土地理院 | 公開地図API |
案1について詳しい設計やPoC用のコードテンプレートを作って
了解です! では、案1:出雲大社周辺の混雑可視化+リアルタイム人数推定について、**設計概要、技術構成、PoC用コードテンプレート(YOLOv8 + Streamlit構成)を詳しくご紹介します!
出雲大社の混雑状況をリアルタイムに可視化し、観光客や運営側に提供。
「いつ行くと空いているか」「回遊エリアの混雑度は?」などを、AIがカメラ映像から人数を自動カウントして判断。
[映像 or 画像入力]
│
▼
[YOLOv8モデルで人物検出]
│
▼
[人数カウント]
(フレームごとにカウント)
│
▼
[Streamlitで可視化]
・現在の人数
・時系列グラフ
・場所別ヒートマップ(応用)
要素 | 使用技術・ライブラリ |
人物検出 | YOLOv8(Ultralytics) |
映像処理 | OpenCV |
Webアプリ | Streamlit |
可視化 | matplotlib / Plotly |
データ管理(簡易) | CSV or SQLite(人数記録) |
(応用)位置情報 | Folium(マップ可視化) |
izumo-crowd-detector/
├── app.py # Streamlitアプリ本体
├── detector.py # YOLOv8ベースの人物検出
├── data/
│ ├── sample.jpg # テスト画像(カメラ映像の代わり)
│ └── history.csv # 人数ログ(時系列記録)
├── model/
│ └── yolov8n.pt # YOLOv8学習済みモデル
├── utils/
│ └── visualizer.py # グラフ・ヒートマップ可視化
└── requirements.txt
# detector.py
from ultralytics import YOLO
import cv2
# モデルロード
model = YOLO("yolov8n.pt") # 軽量モデルでOK
def detect_people(image_path):
image = cv2.imread(image_path)
results = model(image)
count = 0
for r in results:
for box in r.boxes:
cls_id = int(box.cls)
if model.names[cls_id] == "person":
count += 1
return count, image
# app.py
import streamlit as st
from detector import detect_people
import pandas as pd
import datetime
import matplotlib.pyplot as plt
st.title("出雲大社 混雑モニターAI")
uploaded_file = st.file_uploader("カメラ画像をアップロード", type=["jpg", "png"])
if uploaded_file:
# 保存して検出
with open("data/temp.jpg", "wb") as f:
f.write(uploaded_file.read())
count, _ = detect_people("data/temp.jpg")
st.success(f"現在の推定人数:{count}人")
# ログ保存
now = datetime.datetime.now()
new_data = pd.DataFrame([[now, count]], columns=["timestamp", "count"])
try:
df = pd.read_csv("data/history.csv")
df = pd.concat([df, new_data])
except:
df = new_data
df.to_csv("data/history.csv", index=False)
# グラフ表示
st.subheader("人数の推移")
st.line_chart(df.set_index("timestamp")["count"])
ultralytics
opencv-python
streamlit
matplotlib
pandas
※ YOLOv8 を使うには ultralytics パッケージのインストールが必要です
pip install ultralytics
機能 | 説明 |
✅ カメラ映像のリアルタイム処理 | OpenCVのVideoCaptureを使えばライブストリーム可能 |
✅ GPS連携ヒートマップ | 各地点ごとの人数を地図に可視化(Folium) |
✅ 混雑アラート | 一定人数を超えたら通知(Line通知など) |
✅ 複数地点対応 | センサーごとにIDを割り振ってログを分ける |
# visualizer.py
import folium
def create_map(locations_with_count):
m = folium.Map(location=[35.401, 132.685], zoom_start=15) # 出雲大社周辺
for loc, count in locations_with_count:
folium.CircleMarker(
location=loc,
radius=count * 0.5,
color='red',
fill=True,
fill_color='red'
).add_to(m)
return m
yolov8n.pt を Ultralytics公式サイト から取得
サンプル画像(人物が写っているもの)を用意
app.py を実行
streamlit run app.py
画像をアップロード → 人数カウント&ログ保存&グラフ表示!
PoCをブラッシュアップすれば、リアルタイムモニターやWebダッシュボードとして活用可能です。
案2について詳しい設計やPoC用のコードテンプレートを作って
了解です!🌟
では、案2:SNS画像+GPS情報で「人気映えスポット分布図」を生成するPoCについて、詳しい設計とPoC用コードテンプレートを提供します!
このPoCは、観光地の SNS投稿画像を収集・分析し、人気の「映えスポット」を地図に可視化するもので、マーケティング・回遊促進・SNSキャンペーンに非常に役立ちます。
SNS上に投稿された観光写真をもとに、「どこが人気か?」を 地図上に可視化。
出雲・松江などの地域資源の再評価&観光導線の再設計に活用。
[SNS画像 + GPS情報]
│
▼
[画像分類AI]
(例:自然 / 神社仏閣 / 食事 / 人物 など)
│
▼
[場所ごとのカテゴリ投稿数を集計]
│
▼
[Foliumでヒートマップ or カテゴリ別マップ表示]
(観光協会向け可視化ダッシュボード)
要素 | ツール・ライブラリ |
SNS画像収集 | Instagram API、Twitter API、または手動収集 |
GPS抽出 | Pillow + piexif(Exifから位置情報取得) |
画像分類 | PyTorch + 転移学習(ResNet18など) |
地図可視化 | Folium(LeafletベースのPythonマップ可視化) |
UI・分析 | Streamlit or Jupyter Notebook |
sns-map-analyzer/
├── app.py # Streamlitアプリ(ダッシュボード)
├── data/
│ ├── images/ # SNS投稿画像(ダウンロード or サンプル)
│ └── classified.csv # 画像分類+位置情報付きデータ
├── model/
│ └── classifier.pt # 画像分類モデル
├── utils/
│ ├── classify.py # 推論スクリプト
│ └── exif_reader.py # GPS情報抽出
└── requirements.txt
from PIL import Image
import piexif
def get_gps_coordinates(image_path):
img = Image.open(image_path)
exif_data = piexif.load(img.info['exif'])
gps = exif_data.get("GPS", {})
if not gps:
return None
def to_degrees(value):
d, m, s = value
return d[0]/d[1] + m[0]/m[1]/60 + s[0]/s[1]/3600
lat = to_degrees(gps[2])
if gps[1] != b'N':
lat = -lat
lon = to_degrees(gps[4])
if gps[3] != b'E':
lon = -lon
return (lat, lon)
import torch
from torchvision import transforms, models
from PIL import Image
def load_model():
model = models.resnet18(pretrained=False)
model.fc = torch.nn.Linear(model.fc.in_features, 4) # 例:4カテゴリ
model.load_state_dict(torch.load("model/classifier.pt", map_location="cpu"))
model.eval()
return model
def classify_image(image_path, model):
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor()
])
image = Image.open(image_path).convert("RGB")
image = transform(image).unsqueeze(0)
outputs = model(image)
_, pred = torch.max(outputs, 1)
return pred.item()
import streamlit as st
import pandas as pd
import folium
from streamlit_folium import folium_static
st.title("出雲エリアSNS人気映えスポットマップ")
# 分類済みデータ読み込み
df = pd.read_csv("data/classified.csv")
# 地図初期化(出雲大社あたり)
map_center = [35.402, 132.685]
m = folium.Map(location=map_center, zoom_start=13)
# カテゴリ別に色を分けてプロット
colors = ['blue', 'green', 'orange', 'red']
labels = ['自然', '神社仏閣', '料理', '人物']
for _, row in df.iterrows():
folium.CircleMarker(
location=[row['latitude'], row['longitude']],
radius=5,
color=colors[row['class']],
fill=True,
fill_color=colors[row['class']],
popup=labels[row['class']]
).add_to(m)
folium_static(m)
filename,class,latitude,longitude
sunset1.jpg,0,35.4018,132.6831
shrine2.jpg,1,35.4025,132.6867
ramen3.jpg,2,35.4039,132.6899
people4.jpg,3,35.4051,132.6880
torch
torchvision
Pillow
piexif
streamlit
folium
streamlit-folium
pandas
機能 | 内容 |
📸 SNS自動収集 | Instagram Graph APIやTwitter APIを用いて自動で画像+位置情報取得 |
🧠 LLMと組み合わせ | 写真に付いたテキスト(キャプション)をGPTで要約・分析 |
📍 観光施設連携 | 「近くの映えスポットランキング」などを観光アプリに表示 |
🔔 アラート通知 | 一定時間で投稿が急増している場所にマーケティング通知 |
案3について詳しい設計やPoC用のコードテンプレートを作って
了解です!😊
では、案3:石見銀山や松江城での顔認証ベースの回遊分析について、詳しい設計とPoC用のコードテンプレートを提供いたします!
このPoCでは、複数の観光施設を訪れた同一人物を匿名ベースで識別し、回遊傾向を可視化することが目的です。 プライバシーに配慮しながら、観光客の行動傾向を分析する新しい方法として注目されています。
同じ観光客が複数施設(例:石見銀山の資料館 → 武家屋敷 → 大森の町並み)を訪れたことを匿名かつ自動で検出。
施設間の回遊傾向を可視化し、モデルルートの最適化や施設間連携に活用。
[各施設の入り口で顔撮影]
│
▼
[顔特徴量をベクトルとして抽出]
│
▼
[匿名IDを生成(ハッシュ or 類似判定)]
│
▼
[訪問ログに記録(施設名+時刻)]
│
▼
[人物別の訪問経路を可視化]
(グラフ or タイムライン)
機能 | 使用技術・ライブラリ |
顔認証 | face_recognition(dlibベース、簡単・高速) |
類似判定 | 顔特徴量のL2距離で比較 |
データ管理 | SQLite or CSV |
可視化 | Streamlit + Plotly(タイムライン) |
UI | Streamlit |
visitor-tracking/
├── app.py # Streamlitアプリ本体
├── data/
│ ├── faces/ # 撮影された顔画像
│ └── visit_log.csv # 訪問ログ(匿名ID+施設+時間)
├── model/
│ └── known_faces.pkl # 登録済み顔ベクトル
├── utils/
│ ├── face_encoder.py # 顔特徴抽出・類似判定
│ └── visualizer.py # 回遊グラフ描画
└── requirements.txt
import face_recognition
import numpy as np
import os
import pickle
import datetime
def encode_face(image_path):
image = face_recognition.load_image_file(image_path)
locations = face_recognition.face_locations(image)
encodings = face_recognition.face_encodings(image, locations)
if encodings:
return encodings[0] # 最初の顔だけ
else:
return None
def find_match(new_encoding, known_encodings, threshold=0.5):
if not known_encodings:
return None
distances = face_recognition.face_distance(known_encodings, new_encoding)
min_distance = np.min(distances)
if min_distance < threshold:
return np.argmin(distances)
else:
return None
import streamlit as st
import pandas as pd
import pickle
import os
from utils.face_encoder import encode_face, find_match
import datetime
st.title("観光回遊分析(顔ベース匿名認証)")
# データロード
try:
with open("model/known_faces.pkl", "rb") as f:
known_faces = pickle.load(f)
except:
known_faces = []
# CSVログ
log_path = "data/visit_log.csv"
if not os.path.exists(log_path):
pd.DataFrame(columns=["anon_id", "facility", "timestamp"]).to_csv(log_path, index=False)
facility = st.selectbox("現在の施設名", ["石見銀山資料館", "武家屋敷", "町並み交流センター"])
uploaded_file = st.file_uploader("顔画像をアップロード", type=["jpg", "png"])
if uploaded_file:
filepath = os.path.join("data/faces", uploaded_file.name)
with open(filepath, "wb") as f:
f.write(uploaded_file.read())
new_encoding = encode_face(filepath)
if new_encoding is not None:
match_id = find_match(new_encoding, known_faces)
if match_id is not None:
anon_id = f"visitor_{match_id}"
st.success(f"既知の訪問者として記録: {anon_id}")
else:
known_faces.append(new_encoding)
match_id = len(known_faces) - 1
anon_id = f"visitor_{match_id}"
st.success(f"新規訪問者を記録: {anon_id}")
# 保存
with open("model/known_faces.pkl", "wb") as f:
pickle.dump(known_faces, f)
# ログに記録
df = pd.read_csv(log_path)
new_row = pd.DataFrame([[anon_id, facility, datetime.datetime.now()]], columns=df.columns)
df = pd.concat([df, new_row])
df.to_csv(log_path, index=False)
else:
st.error("顔が検出できませんでした")
import pandas as pd
import plotly.express as px
def show_timeline(log_path, visitor_id):
df = pd.read_csv(log_path)
df = df[df["anon_id"] == visitor_id]
df["timestamp"] = pd.to_datetime(df["timestamp"])
df = df.sort_values("timestamp")
fig = px.timeline(df, x_start="timestamp", x_end="timestamp", y="facility", title=f"{visitor_id} の訪問タイムライン")
fig.update_yaxes(categoryorder='total ascending')
return fig
(Streamlit側で表示)
from utils.visualizer import show_timeline
visitor = st.text_input("訪問者IDを入力(例:visitor_0)")
if visitor:
fig = show_timeline(log_path, visitor)
st.plotly_chart(fig)
face_recognition
opencv-python
streamlit
pandas
plotly
対象 | 利点 |
観光協会 | モデルルート設計、観光キャンペーン分析 |
地元施設 | 連携による周遊促進と効果測定 |
自治体 | 滞在時間・混雑分散のデータ化による政策支援 |
このPoCは、顔を使いながら個人特定せずに行動を追えるのが大きな強みです。
観光客が撮った写真の中から 「夕日が美しい画像」をAIで自動選定。
キャンペーン用の投稿画像選定を自動化し、SNS映えするコンテンツを増やす。
自治体・観光協会とのコラボで 地域プロモーションに活用。
[観光客が撮影した画像]
│
▼
[画像アップロード]
(Streamlitアプリ)
│
▼
[画像分類AI]
(夕日 vs その他の風景)
│
├──「夕日」 → SNS投稿候補として保存
└──「その他」 → 処理終了
▼
[選ばれた画像一覧]
(自動タグ・位置情報付きで表示)
要素 | ツール/ライブラリ |
UI | Streamlit |
モデル | PyTorch + 転移学習(例:ResNet18) |
画像処理 | Pillow(画像読込)、OpenCV |
夕日画像 | オープンデータ or 手動収集(Google画像検索でもOK) |
その他 | GPSタグ抽出:piexif / PIL + 位置情報API連携も可 |
bash
sunset-detector/
├── app.py # Streamlitアプリ
├── model/
│ └── sunset_model.pt # 学習済みモデル
├── data/
│ ├── sunset/ # 学習用:夕日画像
│ └── not_sunset/ # 学習用:その他画像
├── utils/
│ └── predict.py # 推論用スクリプト
└── requirements.txt # 必要なライブラリ一覧
# train.py
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torchvision import datasets, models
from torch.utils.data import DataLoader
# データ前処理
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor()
])
dataset = datasets.ImageFolder('data/', transform=transform)
train_loader = DataLoader(dataset, batch_size=16, shuffle=True)
# モデル構築(ResNet18)
model = models.resnet18(pretrained=True)
model.fc = nn.Linear(model.fc.in_features, 2) # 2クラス:夕日 / その他
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 学習ループ(簡略化)
for epoch in range(5):
for images, labels in train_loader:
outputs = model(images)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 保存
torch.save(model.state_dict(), 'model/sunset_model.pt')
# utils/predict.py
from torchvision import transforms, models
from PIL import Image
import torch
def load_model():
model = models.resnet18(pretrained=False)
model.fc = torch.nn.Linear(model.fc.in_features, 2)
model.load_state_dict(torch.load('model/sunset_model.pt', map_location='cpu'))
model.eval()
return model
def predict_image(image_path, model):
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor()
])
image = Image.open(image_path).convert('RGB')
image = transform(image).unsqueeze(0)
outputs = model(image)
_, predicted = torch.max(outputs, 1)
return '夕日' if predicted.item() == 1 else 'その他'
# app.py
import streamlit as st
from utils.predict import load_model, predict_image
from PIL import Image
import os
st.title("宍道湖の夕日画像 自動選定AI")
uploaded_file = st.file_uploader("画像をアップロード", type=['jpg', 'jpeg', 'png'])
if uploaded_file:
img = Image.open(uploaded_file)
st.image(img, caption='アップロード画像', use_column_width=True)
model = load_model()
result = predict_image(uploaded_file, model)
if result == '夕日':
st.success("これは『夕日』画像です!SNS投稿候補に追加されました 🌇")
with open(f'selected/{uploaded_file.name}', 'wb') as f:
f.write(uploaded_file.read())
else:
st.warning("これは夕日の画像ではありません。")
torch
torchvision
streamlit
Pillow
opencv-python
piexif