카테고리 없음

44Day_2021_08_03 (바둑판, 카메라앱)

우리집야옹이룰루 2021. 8. 3. 19:22
728x90
반응형
SMALL

과제 - 바둑판 그리기 

 

마우스 클릭한 위치와 가장 가까운 꼭짓점을 정 중앙으로 원을 그린다.

import cv2
import numpy as np

spot = [[58, 58], [58, 158], [58, 258], [58, 358], [58, 458],
        [158, 58], [158, 158], [158, 258], [158, 358], [158, 458],
        [258, 58], [258, 158], [258, 258], [258, 358], [258, 458],
        [358, 58], [358, 158], [358, 258], [358, 358], [358, 458],
        [458, 58], [458, 158], [458, 258], [458, 358], [458, 458]]
mini = 999

def choose(x, y):
    mini = 999
    for i in range(0, 25):
        dd = ((spot[i][0] - x) ** 2 + (spot[i][1] - y) ** 2) ** 0.5
        if dd < mini:
            mini = dd
            new_x = spot[i][0]
            new_y = spot[i][1]
    return new_x, new_y


mode = True  # 검정

img = np.ones((512, 512, 3), np.uint8) * 255
for i in range(56, 510, 100):
    img = cv2.line(img, (i, 0), (i, 511), (0, 0, 0), 4)
    img = cv2.line(img, (0, i), (511, i), (0, 0, 0), 4)


def draw_circle(event, x, y, flags, param):
    global mode
    if event == cv2.EVENT_LBUTTONDOWN:
        c = 255
        if mode:
            c = 0
        mode = not mode
        new_x, new_y = choose(x,y)
        cv2.circle(img, (new_x, new_y), 20, (c, c, c), -1)
        
        
        if mode:
            new_x, new_y = choose(x,y)
            cv2.circle(img, (new_x, new_y), 21, (0, 0, 0), 1)
            
        cv2.imshow('image', img)


cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
cv2.imshow('image', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

바둑

 

 

카메라 앱

사용 스킬: opencv, thread, tkinter
1) preview: 카메라 영상 실시간 재생
2) 사진 찍기: preview 멈춤
3) 저장: 멈춘 영상을 입력한 파일명으로 파일 저장
4) 동영상 찍기: preview 영상을 임시명으로 동영상 파일 만들어서 저장
5) 동영상 저장: 임시 저장한 파일을 사용자가 입력한 이름으로 파일명 변경

 

 

AppWindow.py

import threading, requests
import tkinter as tk
import cv2
from PIL import Image
from PIL import ImageTk
from tkinter import messagebox
import os


class AppWin(tk.Frame):  # AppWin은 Frame(위젯을 배치하는 판)
    def __init__(self, root=None, geo=None):  # root: Tk() 객체, geo: 창크기 위치
        # fr = tk.Frame(self.root)
        super().__init__(root)  # 부모 생성자에 기본 윈도우 전달
        self.root = root  # 기본 윈도우를 멤버변수로 저장
        self.root.geometry(geo)  # 윈도우의 크기 및 위치 설정
        self.root.resizable(True, True)  # 윈도우의 가로, 세로 크기 재조정 가능으로 설정
        self.pack()

        self.sub_fr = None  # 버튼 배치할 하위 프레임
        self.img_src = None  # 레이블에 출력할 이미지 경로(값)
        self.img_label = None  # 이미지 출력할 레이블
        self.ent_title = None  # 파일명 출력
        self.fileName_ent = None  # 이미지 저장시 파일명 입력받을 엔트리
        # self.service = None  # 카메라 앱 기능이 구현된 서비스 객체 생성
        self.flag = True  # preview 쓰레드를 실행/중지 제어
        self.flag2 = True  # 동영상저장을 실행/중지 제어
        self.pic = None  # 사진 저장을 위해 preview의 마지막 영상을 담을 변수
        self.mode = 1  # 1 : 사진 / 2 : 동영상
        self.create_widgets()

    def read_img(self, path):  # path : 읽을 이미지 경로
        src = cv2.imread(path)  # 이미지 파일에서 영상을 읽음
        src = cv2.resize(src, (640, 400))  # 이미지 가로, 세로 크기 조절하는 함수 opencv[b, g, r]
        img = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)  # opencv[b, g, r] => tkinter[r, g, b]
        img = Image.fromarray(img)  # opencv용 이미지 배열값을 필로우용 이미지로 변환
        self.img_src = ImageTk.PhotoImage(image=img)  # tkinter 용 이미지로 한번더 변환

    def read_cam(self, flag, flag2):
        cap = cv2.VideoCapture(0)
        codec = cv2.VideoWriter_fourcc(*'DIVX')
        out = cv2.VideoWriter('pic/tmp.avi', codec, 25.0, (640, 400))
        while flag():
            ret, src = cap.read()
            if ret:
                src = cv2.resize(src, (640, 400))
                img = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
                img = Image.fromarray(img)
                self.img_src = ImageTk.PhotoImage(image=img)
                # self.img_label['image'] = self.img_src
                self.img_label.configure(image=self.img_src)
                self.img_label.image = self.img_src
                if flag2():
                    out.write(src)  # pic/tmp.avi에 영상 저장
            # cv2.waitKey(100)
        self.pic = src
        cap.release()
        out.release()

    def start_preview(self):  # 미리보기함수. 프로그램시작시 자동으로 호출
        self.flag = True
        # 쓰레드 생성
        th = threading.Thread(target=self.read_cam, args=(lambda: self.flag, lambda: self.flag2))
        th.start()  # 쓰레드 시작

    def btn1_handler(self):  # 사진 촬영 버튼 클릭 시 호출 될 핸들러
        self.flag = False
        self.mode = 1

    def btn2_handler(self):  # 저장 버튼 클릭 시 호출 될 핸들러
        fname = self.fileName_ent.get()  # 엔트리에 입력한 파일명
        if fname == '' or fname == None:
            tk.messagebox.showinfo(title='오류', message='파일명 누락')
            return
        if self.mode == 1:  # 사진 저장
            cv2.imwrite('pic/' + fname + '.jpg', self.pic)
        else:  # 동영상 저장
            os.rename('pic/tmp.avi', 'pic/' + fname + '.avi')
            # os.remove('./tmp.avi')
        self.fileName_ent.delete(0, tk.END)
        self.start_preview()

    def btn3_handler(self):
        self.flag2 = True  # 미리보기에서 동영상 저장 시작
        self.mode = 2  # 저장버튼 눌렀을 때, 파일의 종류를 동영상으로 결정.

    def btn4_handler(self):
        self.flag2 = False  # 미리보기 중지
        self.flag = False  # 미리보기에서 동영상 저장 중지

    def btn5_handler(self):
        fname = self.fileName_ent.get()
        if fname == '' or fname == None:
            tk.messagebox.showinfo(title='오류', message='파일명 누락')
            return
        path = 'pic/' + fname + '.jpg'
        cv2.imwrite(path, self.pic)
        f = open(path, 'rb')
        upload = {'file': f}
        params = {'title': fname + '_title'}
        res = requests.post('http://127.0.0.1:5000/test/upload', files=upload, data=params)
        cont = res.content
        tk.messagebox.showinfo(title='upload', message=cont)
        self.fileName_ent.delete(0, tk.END)
        self.start_preview()

    def create_widgets(self):  # 원하는 구성요소 부착
        self.read_img('start.jpg')
        self.img_label = tk.Label(self, image=self.img_src)
        self.img_label.pack()

        self.ent_title = tk.Label(self, text='파일명 :')
        self.ent_title.pack()

        self.fileName_ent = tk.Entry(self, width=60)
        self.fileName_ent.pack()

        self.sub_fr = tk.Frame(self.root)  # 버튼을 붙일 Frame
        self.sub_fr.pack()
        self.start_preview()

        self.btn1 = tk.Button(self.sub_fr, text='사진 촬영')
        self.btn2 = tk.Button(self.sub_fr, text='저장')
        self.btn3 = tk.Button(self.sub_fr, text='동영상 시작')
        self.btn4 = tk.Button(self.sub_fr, text='동영상 종료')

        # 버튼 그리드 배치
        self.btn1.grid(row=0, column=0)
        self.btn2.grid(row=0, column=1)
        self.btn3.grid(row=0, column=2)
        self.btn4.grid(row=0, column=3)

        # 버튼에 핸들러 등록
        self.btn1['command'] = self.btn1_handler
        self.btn2['command'] = self.btn2_handler
        self.btn3['command'] = self.btn3_handler
        self.btn4['command'] = self.btn4_handler

 

 

Main.py

import camera_app.AppWindow as a
import tkinter as tk


def main():
    win = tk.Tk()  # 윈도우창
    app = a.AppWin(win, '700x600+100+100')
    win.mainloop()


main()

 

 

 

실행을 하게 되면 연결되어있는 카메라가 켜지면서 영상이 보이게 된다.

 

사진 촬영 버튼을 누르게 되면 영상이 멈추고 저장버튼을 눌렀을 때 현재 봉지는 이미지가 저장이 된다.

 

 

동영상 시작 버튼을 누른 시점에서부터 종료 버튼을 누를 때까지 영상이 기록된다.

 

저장할 때에는 파일명을 입력하지 않으면 파일명 누락되었다고 알림 창이 뜨게 된다.

728x90
반응형
LIST