AICCTV 직무연수 실습 자료
수업에 바로 쓰는 인공지능 프로젝트
수업에 바로 쓰는 인공지능 프로젝트
/*
Blink
Turns an LED on for one second, then off for one second, repeatedly.
Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
the correct LED pin independent of which board is used.
If you want to know what pin the on-board LED is connected to on your Arduino
model, check the Technical Specs of your board at:
https://www.arduino.cc/en/Main/Products
modified 8 May 2014
by Scott Fitzgerald
modified 2 Sep 2016
by Arturo Guadalupi
modified 8 Sep 2016
by Colby Newman
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Blink
*/
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(13, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(300); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(300); // wait for a second
}
//아두이노>파일>예제>04.Communication>SerialEvent 예제임
/*
Serial Event example
When new serial data arrives, this sketch adds it to a String.
When a newline is received, the loop prints the string and clears it.
A good test for this is to try it with a GPS receiver that sends out
NMEA 0183 sentences.
NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or
other ATmega32U4 based boards.
created 9 May 2011
by Tom Igoe
This example code is in the public domain.
https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent
*/
String inputString = ""; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
void setup() {
// initialize serial:
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
}
void loop() {
// print the string when a newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}
/*
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
routine is run between each time loop() runs, so using delay inside loop can
delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
//아두이노>파일>예제>04.Communication>SerialEvent 예제 활용
//수신 명령어:on, off
//명령어 처리:13번 포트의 내장 LED를 제어
const int LED = 13; // 테스팅 후 8번 포트로 변경하여 부저도 연결
String inputString = ""; // 수신 명령어 저장
bool stringComplete = false; // 수신 명령문이 완성되었는지 여부
void setup() {
Serial.begin(9600); // 시리얼 통신 초기화(시작)
inputString.reserve(200); //inputString 저장 공간 확보
Serial.println("Serial Start!"); // 통신 시작 알림
pinMode(LED,OUTPUT); //13번 포트(내장LED)를 출력으로 사용함
}
void loop() {
// 입력문자를 모두 받았는가? 줄바꿈(엔터,\n) 문자 왔나?
if (stringComplete) {
Serial.println(inputString);
if (inputString=="on\n"){ //수신 명령이 on이면,
digitalWrite(LED,HIGH); //보드의 LED 켜기
}
if (inputString=="off\n"){ //수신 명령이 off이면,
digitalWrite(LED,LOW); //보드의 LED 끄기
}
// 입력 문자 및 상태 변수 초기화
inputString = "";
stringComplete = false;
}
}
// loop()마치고 다음 loop() 시작 전에 시리얼 입력이 있는지 검사하여, 입력값이 있으면 실행
void serialEvent() {
while (Serial.available()) {
// 시리얼 버퍼에서 바이트 문자 가져오기
char inChar = (char)Serial.read();
// inputString 변수에 들어온 문자를 붙이기
inputString += inChar;
// 들어온 문자가 줄바꿈('\n')이면 입력문자열 완성 알림
if (inChar == '\n') {
stringComplete = true;
}
}
}
//구현 기능: on, off 명령을 수신, LED&부저를 제어, 결과를 송신
//회로 구성: D8 포트에 LED와 부저를 연결
//수신 명령어: on, off, 그 외
//명령어 처리: 8번 포트의 LED&부저를 제어
//송신 메시지: "Warning!", "Normal", "What?"
const int LEDnBUZZ = 8; //LED와 부저 연결 포트
String inputString = ""; // 수신 명령어 저장
bool stringComplete = false; // 수신 명령문이 완성되었는지 여부
void setup() {
Serial.begin(9600); // 시리얼 통신 초기화(시작)
inputString.reserve(200); //inputString 저장 공간 확보
Serial.println("Serial Start!"); // 통신 시작 알림
pinMode(LEDnBUZZ,OUTPUT); //LEDnBUZZ핀을 출력으로 사용
}
void loop() {
// 입력문자를 모두 받았는가? 줄바꿈(엔터,\n) 문자 왔나?
if (stringComplete) {
//Serial.println(inputString); //수신 명령문 출력해보기
if (inputString == "on\n") { //수신 명령이 on이면,
digitalWrite(LEDnBUZZ, HIGH); //LED와 부저 켜기
Serial.println("Warning!"); //처리 결과 전송
}
else if (inputString == "off\n") { //수신 명령이 off이면,
digitalWrite(LEDnBUZZ, LOW); //LED와 부저 끄기
Serial.println("Normal"); //처리 결과 전송
}
else { //수신 명령을 알 수 없다면,
Serial.println("What?");
}
// 입력 문자 및 상태 변수 초기화
inputString = "";
stringComplete = false;
}
}
/*
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
routine is run between each time loop() runs, so using delay inside loop can
delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
# 1_serial_ctrl.py ============
# 명령어: on(Warning), off(Normal), q(종료) '\n'붙여서 보낼 것!
# 입력: 키보드
# 라이브러리 설치: pip install pyserial
import serial
# 아두이노 serial 통신 연결
arduino = serial.Serial('COM3' , 9600)
if arduino.readable():
print('Arduino', arduino.readline().decode()) # 통신 연결 수립 결과 수신 'Serial start!'
cmd = '' # 송신 명령어
while cmd != 'q':
cmd = input('cmd(on/off/q)? ') # 송신 명령어 입력
if cmd == 'on':
cmd += '\n' # 줄바꿈 추가
cmd = cmd.encode('utf-8')
arduino.write(cmd)
print('>> on')
if arduino.readable():
print('<<',arduino.readline().decode())
elif cmd == 'off':
cmd += '\n' # 줄바꿈 추가
cmd = cmd.encode('utf-8')
arduino.write(cmd)
print('>> off')
if arduino.readable():
print('<<',arduino.readline().decode())
티처블머신(TM2)에서 이미지 모델 훈련
클래스
swim : 가위바위보의 바위
help: 가위바위보의 보
none: 빈 화면
이미지 다운로드 swim-samples.zip, help-samples.zip, none-samples.zip
훈련 이미지: 모델 훈련에 사용한 이미지
테스트 이미지: 모델 테스트용 이미지(훈련 완료 후 별도로 수집할 것)
모델 다운로드 converted_keras.zip
keras_model.h5
labels.txt
# 구글 TM2에서 제공하는 코드
from keras.models import load_model
from PIL import Image, ImageOps
import numpy as np
# Load the model
model = load_model('keras_model.h5')
# Create the array of the right shape to feed into the keras model
# The 'length' or number of images you can put into the array is
# determined by the first position in the shape tuple, in this case 1.
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
# Replace this with the path to your image
image = Image.open('<IMAGE_PATH>')
#resize the image to a 224x224 with the same strategy as in TM2:
#resizing the image to be at least 224x224 and then cropping from the center
size = (224, 224)
image = ImageOps.fit(image, size, Image.ANTIALIAS)
#turn the image into a numpy array
image_array = np.asarray(image)
# Normalize the image
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
# Load the image into the array
data[0] = normalized_image_array
# run the inference
prediction = model.predict(data)
print(prediction)
# 테스트 이미지로 모델 테스팅
from keras.models import load_model
from PIL import Image, ImageOps
import numpy as np
# Load the model
model = load_model('./model/keras_model.h5')
# Create the array of the right shape to feed into the keras model
# The 'length' or number of images you can put into the array is
# determined by the first position in the shape tuple, in this case 1.
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
# Replace this with the path to your image
image = Image.open('./image/test/swim/0.jpg')
#resize the image to a 224x224 with the same strategy as in TM2:
#resizing the image to be at least 224x224 and then cropping from the center
size = (224, 224)
image = ImageOps.fit(image, size, Image.ANTIALIAS)
#turn the image into a numpy array
image_array = np.asarray(image)
# Normalize the image
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
# Load the image into the array
data[0] = normalized_image_array
# run the inference
prediction = model.predict(data)
print(prediction)
# 테스트 이미지로 모델 테스팅 한글화 작업
from keras.models import load_model #인공지능 핸들링 모듈
from PIL import Image, ImageOps #pillow 이미지 처리 모듈
import numpy as np #수치 계산 모듈
# 모델 가져오기
model = load_model('./model/keras_model.h5')
# keras모델에 공급하기 위한 빈 배열(리스트) 만들기
# shape(그림갯수, 높이, 폭, 채널)
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
# 이미지 가져오기
image = Image.open('./image/test/swim/0.jpg')
# 티처블머신에 공급하는 이미지 크기
size = (224, 224)
# 티처블머신에 공급하는 크기로 변환
image = ImageOps.fit(image, size, Image.ANTIALIAS)
# 이미지(리스트)를 넘파이 배열로 변환
image_array = np.asarray(image)
# 이미지 정규화
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
# TM2 제공 이미지 data에 넣기
data[0] = normalized_image_array
# 추론 실행
prediction = model.predict(data)
print(prediction)
# openCV로 웹캠을 화면에 표시
# 'q'를 눌러 종료
import numpy as np
import cv2
# 카메라 시작
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 종료 시 terminating async callback 해결
if not cap.isOpened():
print("Could not open webcam")
exit()
while(True):
# 프레임 단위로 캡쳐
ret, frame = cap.read()
# 캡쳐한 프레임 보기
cv2.imshow('quit(q)', frame)
# 키보드 'q'입력,
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 카메라 종료, 모든 창 닫기
cap.release()
cv2.destroyAllWindows()
# 'c'를 누르면 세 가지(캡쳐이미지, 관심영역, 관심영역 축소) 이미지가 image 폴더에 저장됨
# 이미지 캡쳐&저장 구현, 카메라 종료 오류 해결
# 세로 크기 기준으로 정사각형 이미지(관심영역, ROI) 선택
import numpy as np
import cv2
# 카메라 시작
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 종료 시 terminating async callback 해결
if not cap.isOpened():
print("Could not open webcam")
exit()
# 프레임 캡쳐: 웹캠 해상도(width, height) 확인용
ret, frame = cap.read()
if not ret:
print('Camera is not working!')
exit()
print(frame.shape) # 캡쳐 이미지 속성
# roi(관심영역) 설정
W, H = int(cap.get(3)), int(cap.get(4)) # 캡쳐이미지 폭, 높이
x = int((W-H)/2) # 관심영역 x 시작점
while True:
# 프레임 단위로 캡쳐
ret, frame = cap.read()
# roi 영역 복사
roi = frame[0:H, x:x+H].copy() # 모델에 제공할 부분만 복사
cv2.rectangle(frame, (x,0), (x+H, H), (0,255,0)) # 프레임에 사각형 그리기
# 관심영역 사각형을 표시한 프레임 보기
cv2.imshow('quit(q), capture(c)', frame)
# 사이즈 조정 티쳐블 머신에서 사용한 이미지 사이즈로 변경해준다.
size = (224, 224) # TM2 이미지 크기
roi_resized = cv2.resize(roi, size, interpolation=cv2.INTER_AREA)
# 키보드 입력 읽고 처리. c:캡쳐, q:종료
key = cv2.waitKey(25) & 0xFF
if key == ord('q'):
break
elif key == ord('c'):
cv2.imwrite('./image/cap.jpg',frame)
cv2.imwrite('./image/roi.jpg',roi)
cv2.imwrite('./image/roi_resized.jpg',roi_resized)
print(frame.shape, 'cap.jpg image is saved')
print(roi.shape, 'roi.jpg image is saved')
print(roi_resized.shape, 'roi_resized.jpg image is saved')
# 카메라 종료, 모든 창 닫기
cap.release()
cv2.destroyAllWindows()
roi_resized.jpg
# 6_cv2_roi.py 파일과 4_aicctv_img_test_kr.py 파일 합치기
# 웹캠으로 인공지능 추론('c'를 누를 때만)
from keras.models import load_model #인공지능 핸들링 모듈
from PIL import Image, ImageOps #pillow 이미지 처리 모듈
import numpy as np #수치 계산 모듈
import cv2
# numpy 소수 출력 설정(지수표기 안함)
np.set_printoptions(suppress=True)
# 모델 가져오기
model = load_model('./model/keras_model.h5')
# keras모델에 공급하기 위한 빈 배열(리스트) 만들기
# shape(그림갯수, 높이, 폭, 채널)
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
# 카메라 시작
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 종료 시 terminating async callback 해결
if not cap.isOpened():
print("Could not open webcam")
exit()
# 프레임 캡쳐: 웹캠 해상도(width, height) 확인용
ret, frame = cap.read()
if not ret:
print('Camera is not working!')
exit()
# roi(관심영역) 설정
W, H = int(cap.get(3)), int(cap.get(4)) # 캡쳐이미지 폭, 높이
x = int((W-H)/2) # 관심영역 x 시작점
while True:
# 프레임 단위로 캡쳐
ret, frame = cap.read()
# roi 영역 복사
roi = frame[0:H, x:x+H].copy() # 모델에 제공할 부분만 복사
cv2.rectangle(frame, (x,0), (x+H, H-1), (0,255,0)) # 프레임에 사각형 그리기
# 관심영역 사각형을 표시한 프레임 보기
cv2.imshow('quit(q), capture(c)', frame)
# 키보드 입력 읽고 처리. c:캡쳐, q:종료
key = cv2.waitKey(25) & 0xFF
if key == ord('q'):
break
elif key == ord('c'):
# 사이즈 조정 티쳐블 머신에서 사용한 이미지 사이즈로 변경해준다.
size = (224, 224) # TM2 이미지 크기
roi_resized = cv2.resize(roi, size, interpolation=cv2.INTER_AREA)
# 이미지(리스트)를 넘파이 배열로 변환
image_array = np.asarray(roi_resized)
# 이미지 정규화
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
# TM2 제공 이미지 data에 넣기
data[0] = normalized_image_array
# 추론 실행
prediction = model.predict(data)
print(prediction)
클래스의 추론확률 최댓값이 70%(0.7) 이상일 때 추론 인용
인용한 경보 클래스 갯수가 일정 수준을 넘어서면 익사 위험
클래스
0:swim
1:help
2:none
# 위험 경보 아두이노로 전송
# 명령어: on(Warning), off(Normal), q(종료) '\n'붙여서 보낼 것!
# 0:swim 1:help 2:none
from keras.models import load_model #인공지능 핸들링 모듈
from PIL import Image, ImageOps #pillow 이미지 처리 모듈
import numpy as np #수치 계산 모듈
import cv2
import serial
# 아두이노 serial 통신 연결
arduino = serial.Serial('COM3' , 9600)
if arduino.readable():
print('Arduino', arduino.readline().decode()) # 통신 연결 수립 결과 수신 'Serial start!'
# 익사 위험 감지 알고리즘용
MAX_NUM = 60 # 전체 읽은 수 한계값
WARN_NUM = 30 # 경보 발생 경계값
pred = np.zeros(MAX_NUM, dtype=int) # 0이 MAX_NUM개인 배열
warning = 'off\n' # 평화상태
i = 0 # 저장할 pred의 index
# prediction = np.ndarray([0,0,0]) # 추론 결과 저장용
# numpy 소수 출력 설정(지수표기 안함)
np.set_printoptions(suppress=True)
# 모델 가져오기
model = load_model('./model/keras_model.h5')
# keras모델에 공급하기 위한 빈 배열(리스트) 만들기
# shape(그림갯수, 높이, 폭, 채널)
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
# 카메라 시작
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 종료 시 terminating async callback 해결
if not cap.isOpened():
print("Could not open webcam")
exit()
# 프레임 캡쳐: 웹캠 해상도(width, height) 확인용
ret, frame = cap.read()
if not ret:
print('Camera is not working!')
exit()
# roi(관심영역) 설정
W, H = int(cap.get(3)), int(cap.get(4)) # 캡쳐이미지 폭, 높이
x = int((W-H)/2) # 관심영역 x 시작점
while True:
# 프레임 단위로 캡쳐
ret, frame = cap.read()
# roi 영역 복사
roi = frame[0:H, x:x+H].copy() # 모델에 제공할 부분만 복사
cv2.rectangle(frame, (x,0), (x+H, H), (0,255,0)) # 프레임에 사각형 그리기
# 관심영역 사각형을 표시한 프레임 보기
cv2.imshow('quit(q)', frame)
# 키보드 입력 읽고 처리. c:캡쳐, q:종료
key = cv2.waitKey(25) & 0xFF
if key == ord('q'):
break
# 사이즈 조정 티쳐블 머신에서 사용한 이미지 사이즈로 변경해준다.
size = (224, 224) # TM2 이미지 크기
roi_resized = cv2.resize(roi, size, interpolation=cv2.INTER_AREA)
# 이미지(리스트)를 넘파이 배열로 변환
image_array = np.asarray(roi_resized)
# 이미지 정규화
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
# TM2 제공 이미지 data에 넣기
data[0] = normalized_image_array
# 추론 실행
prediction = model.predict(data)
# print(prediction)
# 익사 위험 감지 알고리즘
if np.max(prediction)>0.7: #70%이상 클래스가 있는가?
idx = np.argmax(prediction) # 최댓값의 index(==클래스 번호) 반환
pred[i] = idx # 클래스 번호 저장
i = i+1 # 최댓값의 idx를 pred에 저장
if i == MAX_NUM: # 리스트의 마지막이면 처음으로 가라
i = 0
# pred 보기
for val in pred:
print(val, end='')
print('', end = '\r')
cnt = len(pred[pred==1]) # help(클래스 번호 1) 갯수 세기
if cnt >= WARN_NUM and warning=='off\n': # 평화에서 위험으로 상태 변환 상황인가?
print(cnt, '\n익사위험!!!')
cmd = warning = 'on\n'
# 아두이노로 경보 보내기
cmd = cmd.encode('utf-8')
arduino.write(cmd)
print('>> on')
# 아두이노에서 결과 수신
if arduino.readable():
print('<<',arduino.readline().decode())
#ToDo: 카카오톡 문자 보내기
elif cnt < WARN_NUM and warning=='on\n': # 위험에서 평화로 상태 변환 상황인가?
print(cnt,'\n평화로움')
cmd = warning = 'off\n'
# 아두이노로 경보 보내기
cmd = cmd.encode('utf-8')
arduino.write(cmd)
print('>> off')
# 아두이노에서 결과 수신
if arduino.readable():
print('<<',arduino.readline().decode())
#ToDo: 카카오톡 문자 보내기
# 6_cv2_roi.py 파일과 4_aicctv_img_test_kr.py 파일 합치기
# 웹캠으로 인공지능 추론('c'를 누를 때만)
from keras.models import load_model #인공지능 핸들링 모듈
from PIL import Image, ImageOps #pillow 이미지 처리 모듈
import numpy as np #수치 계산 모듈
import cv2
# numpy 소수 출력 설정(지수표기 안함)
np.set_printoptions(suppress=True)
# 모델 가져오기
model = load_model('./model/keras_model.h5')
# keras모델에 공급하기 위한 빈 배열(리스트) 만들기
# shape(그림갯수, 높이, 폭, 채널)
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32)
# 카메라 시작
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 종료 시 terminating async callback 해결
if not cap.isOpened():
print("Could not open webcam")
exit()
# 프레임 캡쳐: 웹캠 해상도(width, height) 확인용
ret, frame = cap.read()
if not ret:
print('Camera is not working!')
exit()
# roi(관심영역) 설정
W, H = int(cap.get(3)), int(cap.get(4)) # 캡쳐이미지 폭, 높이
x = int((W-H)/2) # 관심영역 x 시작점
while True:
# 프레임 단위로 캡쳐
ret, frame = cap.read()
# roi 영역 복사
roi = frame[0:H, x:x+H].copy() # 모델에 제공할 부분만 복사
cv2.rectangle(frame, (x,0), (x+H, H-1), (0,255,0)) # 프레임에 사각형 그리기
# 관심영역 사각형을 표시한 프레임 보기
cv2.imshow('quit(q), capture(c)', frame)
# 키보드 입력 읽고 처리. c:캡쳐, q:종료
key = cv2.waitKey(25) & 0xFF
if key == ord('q'):
break
elif key == ord('c'):
# 사이즈 조정 티쳐블 머신에서 사용한 이미지 사이즈로 변경해준다.
size = (224, 224) # TM2 이미지 크기
roi_resized = cv2.resize(roi, size, interpolation=cv2.INTER_AREA)
# 이미지(리스트)를 넘파이 배열로 변환
image_array = np.asarray(roi_resized)
# 이미지 정규화
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
# TM2 제공 이미지 data에 넣기
data[0] = normalized_image_array
# 추론 실행
prediction = model.predict(data)
print(prediction)
import requests
import json
import time
def sendmsg(msg):
#1.
with open(r"c:/AICCTV/kakao/kakao_code.json","r") as fp:
tokens = json.load(fp)
#2.
# with open("kakao_code.json","r") as fp:
# tokens = json.load(fp)
url="https://kapi.kakao.com/v2/api/talk/memo/default/send"
# kapi.kakao.com/v2/api/talk/memo/default/send
headers={
"Authorization" : "Bearer " + tokens["access_token"]
}
data={
"template_object": json.dumps({
"object_type":"text",
"text":msg + time.strftime('%Y-%m-%d \n%H:%M:%S'),
"link":{
"web_url":"www.naver.com"
}
})
}
response = requests.post(url, headers=headers, data=data)
response.status_code
print(response.status_code, end=' ')
if response.json().get('result_code') == 0:
print('카카오톡으로 메시지 전송함~~')
else:
print('카카오톡으로 메시지 전송 실패! 오류메시지 : ' + str(response.json()))