import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import numpy as np #pip install numpy
import tensorflow as tf
# pip install --upgrade pip
# pip install tensorflow
# python이 32bit으로 깔려있다면, 오류가 남 -> window에서 지워주시고 다시 64비트로 설치해주세요.
# ERROR: Could not find a version that satisfies the requirement tensorflow (from versions: none)
# ERROR: No matching distribution found for tensorflow
class 무인가게프로그램(QMainWindow):
def __init__(self):
super().__init__()
self.UI초기화()
def UI초기화(self):
self.예측정보리스트 = {
0 : ["티셔츠", 5000],
1 : ["트라우저 진", 30000],
2 : ["스웨터", 15000],
3 : ["드레스", 50000],
4 : ["코트", 50000],
5 : ["샌들", 10000],
6 : ["셔츠", 15000],
7 : ["스니커즈", 30000],
8 : ["가방", 5000],
9 : ["부츠", 40000]}
self.가게이름 = QLabel('라이캣의 무인가게', self)
self.가게이름.setFont(QFont("Decorative", 20))
self.가게이름.adjustSize()
self.가게이름.move(180, 30)
self.이미지 = QLabel(self)
self.이미지.move(170, 100)
self.가이드 = QLabel('File을 눌러 모델 추가 후 이미지 삽입하여 인식', self)
self.가이드.move(150, 500)
self.가이드.adjustSize()
self.계좌번호 = QLabel('(주)생선가게 위니브은행 999-999999-9999', self)
self.계좌번호.move(200, 550)
self.계좌번호.adjustSize()
self.계좌번호.setHidden(True)
self.이미지업로드 = QPushButton("이미지 업로드", self)
self.이미지업로드.move(170, 430)
self.이미지업로드.setEnabled(False)
self.이미지업로드.clicked.connect(self.loadImage)
self.결제버튼 = QPushButton("결제하기", self)
self.결제버튼.move(370, 430)
self.결제버튼.setEnabled(False)
self.인식모델 = None
메뉴바 = self.menuBar()
메뉴바.setNativeMenuBar(False)
파일메뉴 = 메뉴바.addMenu('File')
모델불러오기메뉴 = QAction('모델 불러오기', self)
모델불러오기메뉴.setShortcut('Ctrl+L')
모델불러오기메뉴.triggered.connect(self.loadModel)
파일메뉴.addAction(모델불러오기메뉴)
self.setWindowTitle('무인상점 만들기')
self.setGeometry(300, 300, 600, 600)
self.show()
def loadModel(self):
try:
모델파일, _ = QFileDialog.getOpenFileName(self, '모델 추가', '')
if 모델파일:
self.인식모델 = tf.keras.models.load_model(
모델파일)
self.가이드.setText('모델 추가 완료!')
self.이미지업로드.setEnabled(True)
except:
self.가이드.setText("모델 파일이 아닙니다.")
def loadImage(self):
이미지이름 = QFileDialog.getOpenFileName(self, 'Open file', './')
이미지파일 = QPixmap(이미지이름[0]).scaled(
300, 300, aspectRatioMode=Qt.KeepAspectRatio)
self.이미지.setPixmap(이미지파일)
self.이미지.adjustSize()
if 이미지파일:
행렬 = np.zeros((28, 28))
for 행 in range(28):
for 열 in range(28):
행렬[열, 행] = 1 - QImage(QPixmap(이미지이름[0]))\\
.scaled(28,28).pixelColor(행, 열).getRgb()[0] / 255.0
# 이미지를 압축시켜 음영의 효과로 구분하여 요소들을 추가
행렬 = 행렬.reshape(-1, 28, 28)
예측 = self.인식모델.predict(행렬)[0] # 이미지 인식 진행
결과 = np.argmax(예측) # 제일 높게 나온 예측 값
self.가이드.setText("선택하신 제품은 " + str(self.예측정보리스트.get(결과)[0])\\
+ "이고 결재하실 금액은 "\\
+ "{:,}".format(self.예측정보리스트.get(결과)[1])\\
+ '원 입니다.')
self.가이드.adjustSize()
self.가이드.move(150, 500)
self.계좌번호.setHidden(False)
self.결제버튼.setEnabled(True)
프로그램무한반복 = QApplication(sys.argv)
실행인스턴스 = 무인가게프로그램()
프로그램무한반복.exec_()
여기서는 MNIST라고 하는 예제를 사용해서 간단하게 사물인식을 해볼 예정인데요. MNIST라고 한다면 인공지능을 처음 공부해보시는 분들이 print('hello world')
처럼 가장 처음에 하시는 예제입니다.
그중에서도 fashion에 관련해서 여러가지 사물을 인식할 수 있는 MNIST를 해보도록 하겠습니다. (기초 MNIST는 손글씨 인식하기 입니다.)
GUI 설계
self.store = QLabel('라이캣의 무인가게', self)
self.store.setFont(QFont("Decorative", 20))
self.store.adjustSize()
self.store.move(180, 30)
self.label = QLabel(self)
self.label.move(170, 100)
self.label2 = QLabel('File을 눌러 모델 추가 후 이미지 삽입하여 인식', self)
self.label2.move(150, 500)
self.label2.adjustSize()
self.label3 = QLabel('(주)생선가게 위니브은행 999-999999-9999', self)
self.label3.move(200, 550)
self.label3.adjustSize()
self.label3.setHidden(True)
self.uploadPicture = QPushButton("사진 업로드", self)
self.uploadPicture.move(170, 430)
self.uploadPicture.setEnabled(False)
self.uploadPicture.clicked.connect(self.loadImage)
self.Model = None
menubar = self.menuBar()
menubar.setNativeMenuBar(False)
filemenu = menubar.addMenu('File')
load_model = QAction('모델 불러오기', self)
load_model.setShortcut('Ctrl+L')
load_model.triggered.connect(self.loadModel)
filemenu.addAction(load_model)
여기서 어떻게 물체를 인식할 수 있는지, 머신러닝은 어떻게 학습을 하는지는 강의의 범주를 넘어선다 생각하여 아래 문서로 대체합니다. 영상 강의에서는 이 부분을 좀 더 상세하게 다룹니다.
실행 결과
인식 모델은 어떻게 동작할까?
첫 번째 신경망 훈련하기: 기초적인 분류 문제 | TensorFlow Core
패션 MNIST 데이터셋 신경망 사용법 튜토리얼
모델 저장과 복원
생활 코딩 홈페이지의 머신러닝 관련된 자료입니다.
학습된 모델을 다운 받을 수 있는 깃허브 페이지입니다.
위 이미지 중 fashion.h5를 다운로드 받아주시면 됩니다.
앞서 한 번 보여드렸던 모델이 인식할 수있는 이미지에 레이블입니다.
인식된 결과값을 나타내기 위해 딕셔너리로 정의해 매핑합니다.
self.예측정보리스트 = {
0 : ["티셔츠", 5000],
1 : ["트라우저 진", 30000],
2 : ["스웨터", 15000],
3 : ["드레스", 50000],
4 : ["코트", 50000],
5 : ["샌들", 10000],
6 : ["셔츠", 15000],
7 : ["스니커즈", 30000],
8 : ["가방", 5000],
9 : ["부츠", 40000]}
모델 추가 함수 작성
def loadModel(self):
try:
fname, _ = QFileDialog.getOpenFileName(self, '모델 추가', '')
if fname:
self.Model = tf.keras.models.load_model(
fname)
self.label2.setText('모델 추가 완료!')
self.uploadPicture.setEnabled(True)
except:
self.label2.setText("모델 파일이 아닙니다.")
이미지 추가 함수 작성
def loadImage(self):
iname = QFileDialog.getOpenFileName(self, 'Open file', './')
image = QPixmap(iname[0]).scaled(
300, 300, aspectRatioMode=Qt.KeepAspectRatio)
# 라벨에 표시해주기 위해 압축을 진행
self.label.setPixmap(image)
self.label.adjustSize()
getOpenFileName()으로 파일 가져오기
scaled 함수를 통해 이미지가 크더라도 라벨 크기에 맞도록 압축을 진행
이미지 인식 코드
if image:
arr = np.zeros((28, 28)) # 28X 28의 행렬을 만들어
for i in range(28):
for j in range(28):
arr[j, i] = 1 - QImage(QPixmap(iname[0])).scaled(28, 28)\\
.pixelColor(i, j).getRgb()[0] / 255.0
arr = arr.reshape(-1, 28, 28)
predictions = self.Model.predict(arr)[0]
result = np.argmax(predictions)
self.가이드.setText("선택하신 제품은 "\\
+ str(self.예측정보리스트.get(결과)[0])\\
+ "이고 결재하실 금액은 "\\
+ "{:,}".format(self.예측정보리스트.get(결과)[1])\\
+ '원 입니다.')
간단히 설명하자면 이미지 인식은 이미지를 행렬형태로 변환하여 음영의 효과로 구분하여 각 행렬의 값을 높여 인식합니다. 즉, 행렬의 요소를 파악하여 이미지 인식 진행합니다.
np.zeros((28, 28)) : 28x28의 행렬을 만들고
arr[j, i] = 1 - QImage(QPixmap(iname[0])).scaled(28,28)\\
.pixelColor(i, j).getRgb()[0] / 255.0
모델은 아래와 같은 행렬의 형태로 학습이 진행됩니다. 아래 이미지는 '신발'입니다.
즉, 이미지를 압축시켜 rgb값을 통해 음영의 효과로 구분하여 각 행렬의 값을 증가시킵니다.
이미지 인식 진행
arr = arr.reshape(-1, 28, 28)
predictions = self.Model.predict(arr)[0]
result = np.argmax(predictions)
self.가이드.setText("선택하신 제품은 "\\
+ str(self.예측정보리스트.get(결과)[0])\\
+ "이고 결재하실 금액은 "\\
+ "{:,}".format(self.예측정보리스트.get(결과)[1])\\
+ '원 입니다.')
reshape(-1, 28, 28) 은 배열을 재구조하는 함수입니다.
[Python NumPy] reshape에서 -1 은 무슨 의미인가? (reshape(-1, 1))
참고 자료
self.Model.predict(arr)[0] : 이미지를 예측합니다.
np.argmax(predictions) : 제일 높게 예측된 값 반환합니다.
self.acc.get(result)[0] : 인식된 값이 무엇인지 선언한 딕셔너리에서 가져옵니다.
self.acc.get(result)[1] : 인식된 값의 가격을 구합니다.
"{:,}".format : 천 단위로 출력할 때 쓰는 문법입니다.
self.label3.setHidden(False)
self.pay.setEnabled(True)