728x90

SSD 얼굴 검출

import sys
import numpy as np
import cv2


model = 'opencv_face_detector/res10_300x300_ssd_iter_140000_fp16.caffemodel'
config = 'opencv_face_detector/deploy.prototxt'
# model = 'opencv_face_detector/opencv_face_detector_uint8.pb'
# config = 'opencv_face_detector/opencv_face_detector.pbtxt'

# cap = cv2.VideoCapture('utub.mp4')
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print('Camera open failed!')
    sys.exit()

net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

while True:
    ret, frame = cap.read()

    if not ret:
        break
    
    #1: 픽셀 0~255
    #resize 크기(300,300)
    #BGR 평균 (104,177,123) 
    blob = cv2.dnn.blobFromImage(frame, 1, (300, 300), (104, 177, 123))
    net.setInput(blob)
    out = net.forward() #(1,1,200,7) 에서 (200,7)만 필요함  *꼭 200이 아닐수 있음
    
    detect = out[0, 0, :, :] #detect 이차원 행렬을 분석한다.
    (h, w) = frame.shape[:2]

    for i in range(detect.shape[0]): #전체 행만큼 순회
        confidence = detect[i, 2] #confidence: 얼굴일 확률
        if confidence < 0.5:
            break
        # print('detect[i, 3]',detect[i, 3])
        #좌표가0~1로 정규화 되어 있으므로 크기를 직접 곱해서 좌표를 구한다    
        #x1,y1:좌측상단       
        x1 = int(detect[i, 3] * w)
        y1 = int(detect[i, 4] * h)
        
        # x2,y2: 우측하단
        x2 = int(detect[i, 5] * w)
        y2 = int(detect[i, 6] * h)

        cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0))

        label = f'Face: {confidence:4.2f}'
        # (x1, y1-1): text 위치 지정
        cv2.putText(frame, label, (x1, y1-1), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 1, cv2.LINE_AA)

    cv2.imshow('frame', frame)

    if cv2.waitKey(1) == 27:
        break

cv2.destroyAllWindows()

 

yolo_v3 객체 검출

import sys
import numpy as np
import cv2


# 모델 & 설정 파일
model = 'yolo_v3/yolov3.weights'
config = 'yolo_v3/yolov3.cfg'
class_labels = 'yolo_v3/coco.names'
confThreshold = 0.5
nmsThreshold = 0.4

# 테스트 이미지 파일
img_files = ['person.jpg', 'sheep.jpg', 'kite.jpg']

# 네트워크 생성
net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

# 클래스 이름 불러오기

classes = [] #총 80개가 들어옴
with open(class_labels, 'rt') as f:
    classes = f.read().rstrip('\n').split('\n')

#low=0, high=255, size=(80,3)
#3은 RGB
colors = np.random.uniform(0, 255, size=(len(classes), 3)) #80개 각각 다른 색깔

# 출력 레이어 이름 받아오기
# 출력을 하는 3개의 layer 이름을 뽑는다
layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# output_layers = ['yolo_82', 'yolo_94', 'yolo_106'] 
'''
* 첫번째 82번 layer: 13*13영상 *3(RGB)=507에다가
컬럼은 총 85개 인데 순서대로 x,y,w,h,confidences,80개 클래스(해당 클래스일 확률이 들어감)
종합해서 507*8,
* 두번째 94번 layer: 2028,85
* 세번재 106번 layer: 8112,85
'''

# 실행

for f in img_files:
    img = cv2.imread(f)

    if img is None:
        continue

    # 블롭 생성 & 추론
    blob = cv2.dnn.blobFromImage(img, 1/255., (416, 416), swapRB=True)
    net.setInput(blob)

    
    #forward(문자열 리스트):문자열에 해당하는 레이어의 out을 outs에 전달
    outs = net.forward(output_layers)

    # outs는 3개의 ndarray 리스트.
    # 아래 값은 입력이 416일때
    # outs[0].shape=(507, 85), 13*13*3=507
    # outs[1].shape=(2028, 85), 26*26*3=2028
    # outs[2].shape=(8112, 85), 52*52*3=8112

    h, w = img.shape[:2]

    class_ids = []
    confidences = []
    boxes = []

    for out in outs:
        #하나의 행 씩 85개중 앞에 4개는 바운딩박스의 좌표값
        # 그 다음은 objectness Score, 나머지 80개는 Class Scores(80개 클래스에 대한 각각의 확률값)
        for detection in out:
            # detection: 4(bounding box) + 1(objectness_score) + 80(class confidence)
            scores = detection[5:] #80개 클래스 확률값 
            class_id = np.argmax(scores) #80개 클래스 중에서 가장 최대값을 가지는 확률값의 인덱스
            confidence = scores[class_id]
    
            if confidence > confThreshold: #클래스에 대한 확률값이 confThreshold 이상인 경우에만바운딩박스를 취합한다
                # 바운딩 박스 중심 좌표 & 박스 크기
                
                #cx,cy: 바운딩박스 센터좌표
                cx = int(detection[0] * w)
                cy = int(detection[1] * h)
                bw = int(detection[2] * w)
                bh = int(detection[3] * h)

                # 바운딩 박스 좌상단 좌표
                sx = int(cx - bw / 2)
                sy = int(cy - bh / 2)

                #boxes안에 객체 검출할때 쓰인 모든 박스 정보가 들어있다
                #이중에서 대표 박스 하나를 골라야 하므로 NMSBoxes를 사용해야한다
                boxes.append([sx, sy, bw, bh]) 
                confidences.append(float(confidence))
                class_ids.append(int(class_id)) #인식한 객체가 인덱스로 정리되어 있음

    # 비최대 억제
    '''
    한 객체에 여러 바운딩 박스가 있으므로 이 여러 박스 중 가장 좋은 박스를 뽑아내기
    예를들어 두 박스가 있는데 이 겹쳐진 부분이 nmsThreshold%만큼 겹쳐진 것들중
    confidence 값이 confThreshold이상인 것들중에 가장 큰 confidence를 갖는 하나만 골라서 
    indices에 넣기(몇번째 박스인지에 대한 정보)
    '''
    #정리:40% 이상 겹치는 바운딩 박스에 대해 최대 confidence (>0.5)바운딩 박스만 선별
    #nmsThreshold값이 0.99라면 99%이상의 공간을 같이 공유하는 박스들이 겹치게 될것
    # indices.shape=(N, 1)
    indices = cv2.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)

    for i in indices: #각 객체당 선별된 박스가 for loop를 통해 정보 추출
        # print(i)
        i = i[0]
        print
        sx, sy, bw, bh = boxes[i]
        label = f'{classes[class_ids[i]]}: {confidences[i]:.2}'
        color = colors[class_ids[i]]
        cv2.rectangle(img, (sx, sy, bw, bh), color, 2)
        cv2.putText(img, label, (sx, sy - 10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2, cv2.LINE_AA)

    #getPerfProfile: 실행시간 계산에 관련된 함수  
    t, _ = net.getPerfProfile()
    label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
    cv2.putText(img, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 1, cv2.LINE_AA)

    cv2.imshow('img', img)
    cv2.waitKey()

cv2.destroyAllWindows()

 

Mask_rcnn

import sys
import numpy as np
import cv2


def drawBox(img, classId, conf, left, top, right, bottom):
    # Draw a bounding box.
    cv2.rectangle(img, (left, top), (right, bottom), colors[classId], 2)

    label = f'{classes[classId]}: {conf:.2f}'

    labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)
    top = max(top, labelSize[1])
    cv2.rectangle(img, (left - 1, top - labelSize[1] - baseLine),
                  (left + labelSize[0], top), colors[classId], -1)
    cv2.putText(img, label, (left, top - baseLine), cv2.FONT_HERSHEY_SIMPLEX,
                0.6, (0, 0, 0), 1, cv2.LINE_AA)


# 모델 & 설정 파일
model = 'mask_rcnn/frozen_inference_graph.pb'
config = 'mask_rcnn/mask_rcnn_inception_v2_coco_2018_01_28.pbtxt'
class_labels = 'mask_rcnn/coco_90.names'
confThreshold = 0.6
maskThreshold = 0.3

# 테스트 이미지 파일
img_files = ['dog.jpg', 'traffic.jpg', 'sheep.jpg']

# 네트워크 생성
net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

# 클래스 이름 불러오기

classes = []
with open(class_labels, 'rt') as f:
    classes = f.read().rstrip('\n').split('\n')

colors = np.random.uniform(0, 255, size=(len(classes), 3))

# 전체 레이어 이름 받아오기
'''
객체를 바운딩박스 치는 output: (1,1,100,7) => 최대100개까지 객체 검출 가능 하며 7은 클래스 정보 또는 바운딩박스정보
바운딩 된 객체에서 윤곽선을 도출하는 output: (100,90,15,15) => 90개 class에 대한 15*15마스크가 출력된다
                                                        각각의 100개 객체에 대해서 90개의 마스크맵을 출력으로 준다   
'''

layer_names = net.getLayerNames() #네트워크의 모든 레이어 이름 가져오기
# net.getUnconnectedOutLayers(): 출력 레이어의 인덱스를 가져오기(인덱스는 332)
# output_layers: detection_masks 1개(출력레이어)
# 위 내용을 가지고 생각해 보면 네트워크 layer 중에서 마지막 출력 레이어는 네트워크 레이어에 포함되지 않는다는 걸로 연결됨
# 레이어 종류가 네트워크 레이어, 출력 레이어 이렇게 두개로 나뉜걸로 생각할수 있음(뇌피셜이라 확실치 않음)
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
for name in  layer_names:
    print(name)

# 실행

for f in img_files:
    img = cv2.imread(f)

    if img is None:
        continue

    # 블롭 생성 & 추론

    #blob의 사이즈는 지정 안해도 됨->이미지 크기와 동일한 크기로 만들어줌
    #평균값 디폴트는 0 이므로 여기서는 따로 지정 안함
    blob = cv2.dnn.blobFromImage(img, swapRB=True) #RGB로 학습되어 있음
    net.setInput(blob)

    #detection_out_final: 바운딩박스 정보
    #detection_masks: 각각의 바운딩 박스에서 마스크 정보를 가지고 있음
    #큰 순서: 각 객체의 바운딩박스 정보를 추출한 후에 그 박스 안에 있는 객체윤곽를 추출
    boxes, masks = net.forward(['detection_out_final', 'detection_masks'])

    # boxes.shape=(1, 1, 100, 7)
    # masks.shape=(100, 90, 15, 15)
    '''
    객체를 바운딩박스 치는 output: (1,1,5,7) => 5개 객체 검출함 클래스명을 직접 조사했지만 dog사진에 4개이상의 클래스명은 찾을수 없었다
                                                다시말해 같은 객체를 중복하여 검출했을 거라 생각해 볼수 있다. 
        바운딩 된 객체에서 윤곽선을 도출하는 output: (100,90,15,15) => 90개 class에 대한 15*15마스크가 출력된다
                                                         각각의 100개 객체에 대해서 90개의 마스크맵을 출력으로 준다   
    '''
    h, w = img.shape[:2]
    numClasses = masks.shape[1]  # 90(coco dataset의 class 개수)
    numDetections = boxes.shape[2]  # 5(detection 개수, 100개가 기본값이며 이보다 낮게 나올수도 있다)

    boxesToDraw = []
    for i in range(numDetections):
        box = boxes[0, 0, i]  # box.shape=(7,) 검출된 5개 객체의 바운딩 박스 정보를 가져온다
                              # (7,)짜리가 5개가 있는것이다.
        # classID: 몇번째에 대한 바운딩 박스 인가를 나타냄
        # confidence: 확률값(임계값보다 커야 제대로 찾았다고 인식한다)
        # 입력영상의 크기가 0~1 정규화가 되었다는 가정 하에 x1y1:좌측상단 , x2y2:우측하단
        #box: (0,classID,confidence, x1,y1,x2,y2) -> (7,)
        
        #i번째 객체 검출한것에 대해서 15*15 마스크 맵이 90개가 있는 것
        #90개 마스크를 다 쓰는게 아니라 94번줄의 ClassId에 해당하는 것만 사용
        mask = masks[i]  # mask.shape=(90, 15, 15)
        score = box[2] #confidence값
        if score > confThreshold: # 임계값보다 커야 제대로 찾은 것이다.
            classId = int(box[1]) #classID 추출
            #print(classId, classes[classId], score)

            #변환된 좌표
            x1 = int(w * box[3])
            y1 = int(h * box[4])
            x2 = int(w * box[5])
            y2 = int(h * box[6])

            #변환된 좌표와 원래 img크기를 비교해서
            #변환된 좌표가 본 이미지 크기보다 큰 경우를 없애기 위한 코드?
            x1 = max(0, min(x1, w - 1))
            y1 = max(0, min(y1, h - 1))
            x2 = max(0, min(x2, w - 1))
            y2 = max(0, min(y2, h - 1))

            boxesToDraw.append([img, classId, score, x1, y1, x2, y2])
            
            # classMask: 15*15짜리 행렬의 float형태의 마스크
            # 이 안에서 배경에 해당하는 부분은 값이 작을것이고, 객체에 해당하는 건 값이 크다
            classMask = mask[classId] #ClassID에 해당하는 mask 정보를 가져온다

            # 객체별 15x15 마스크를 바운딩 박스 크기로 resize한 후, 불투명 컬러로 표시
            classMask = cv2.resize(classMask, (x2 - x1 + 1, y2 - y1 + 1)) 
            
            #바운딩박스 안에는 배경과 객체가 있는데, 어떠한 기준값이 있어야 객체와 배경을 구분할수가 있다
            #이 구분하기 위한 기준 값이 maskThreshold (maskThreshold보다 크면 객체 아니면 배경)
            mask = (classMask > maskThreshold)

            #객체마다 다른 색깔로 불투명하게 하는 코드-> 결과영상에서 클래스 윤곽정보를 보여줌
            roi = img[y1:y2+1, x1:x2+1][mask] #원본 실제 객체 이미지
            img[y1:y2+1, x1:x2+1][mask] = (0.7 * colors[classId] + 0.3 * roi).astype(np.uint8)

    # 객체별 바운딩 박스 그리기 & 클래스 이름 표시-> 이게 없으면 결과영상에서 바운딩 박스가 없다
    for box in boxesToDraw:
        drawBox(*box)

    t, _ = net.getPerfProfile()
    label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
    cv2.putText(img, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 1, cv2.LINE_AA)

    cv2.imshow('img', img)
    cv2.waitKey()

cv2.destroyAllWindows()

 

OpenPose

import sys
import numpy as np
import cv2


# 모델 & 설정 파일
model = 'openpose/pose_iter_440000.caffemodel'
config = 'openpose/pose_deploy_linevec.prototxt'

# 포즈 점 개수, 점 연결 개수, 연결 점 번호 쌍
nparts = 18 #전체 점의 개수
npairs = 17 # 점과 점 사이를 잇는 직선의 개수(관절표현)

#관절을 어떻게 이을건지를 설정해준다
pose_pairs = [(1, 2), (2, 3), (3, 4),  # 왼팔: 1번점 2번점, 2번점 3번점, 3번점 4번점을 연결하면 왼팔이된다
              (1, 5), (5, 6), (6, 7),  # 오른팔
              (1, 8), (8, 9), (9, 10),  # 왼쪽다리
              (1, 11), (11, 12), (12, 13),  # 오른쪽다리
              (1, 0), (0, 14), (14, 16), (0, 15), (15, 17)]  # 얼굴

# 테스트 이미지 파일
img_files = ['pose1.jpg', 'pose2.jpg', 'pose3.jpg']

# 네트워크 생성
net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

for f in img_files:
    img = cv2.imread(f)

    if img is None:
        continue

    # 블롭 생성 & 추론
    blob = cv2.dnn.blobFromImage(img, 1/255., (368, 368))
    net.setInput(blob)
    out = net.forward()  # out.shape=(1, 57, 46, 46) 46*46가 57개, 앞에서 18개만 사용(keypoint)

    h, w = img.shape[:2]

    # 검출된 점 추출
    points = []
    for i in range(nparts): #nparts:18

        #heatMap 46*46 짜리 행렬이된다
        #heatMap 모양: 관절 부분 point 부분에서 headmap생김
        heatMap = out[0, i, :, :] #46*46의 float32 행렬

        '''
        ##heatmap 시각화##
        heatImg = cv2.normalize(heatMap, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) #0~1 -> 0~255
        heatImg = cv2.resize(heatImg, (w, h))
        heatImg = cv2.cvtColor(heatImg, cv2.COLOR_GRAY2BGR)
        heatImg = cv2.addWeighted(img, 0.5, heatImg, 0.5, 0)
        cv2.imshow('heatImg', heatImg)
        cv2.waitKey()
        '''
        #point: 46*46 행렬에서의 최대값 위치
        _, conf, _, point = cv2.minMaxLoc(heatMap)

        #point 최대값 위치가 전체 영상에서는 어디에 위치해 있는가를 알기 위함->w,h 곱셈
        #입력영상 해상도에 맞는 특정 관절 위치 x,y => (21,9) 위치를 정 사이즈로 변환
        x = int(w * point[0] / out.shape[3]) #out.shape[3]:46,  point[0]:21
        y = int(h * point[1] / out.shape[2]) #out.shape[2]:46,  point[1]:9

        points.append((x, y) if conf > 0.1 else None)  # heat map threshold=0.1

    # 검출 결과 영상 만들기 
    for pair in pose_pairs:
        p1 = points[pair[0]]
        p2 = points[pair[1]]

        if p1 is None or p2 is None: #67번줄에서 None이 들어오면 무시
            continue

        cv2.line(img, p1, p2, (0, 255, 0), 3, cv2.LINE_AA)

        #각각의 끝점을 원으로 그리기
        cv2.circle(img, p1, 4, (0, 0, 255), -1, cv2.LINE_AA)
        cv2.circle(img, p2, 4, (0, 0, 255), -1, cv2.LINE_AA)

    # 추론 시간 출력
    t, _ = net.getPerfProfile()
    label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
    cv2.putText(img, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 1, cv2.LINE_AA)

    cv2.imshow('img', img)
    cv2.waitKey()

cv2.destroyAllWindows()

 

728x90

'실습 note' 카테고리의 다른 글

bitcoin 예측 실습  (0) 2021.04.14
제조 공정 불량 검출 실습  (0) 2021.03.11
OpenCV_11(딥러닝)  (0) 2021.03.04
OpenCV_10(머신러닝)  (0) 2021.03.03
OpenCV_9(객체 추적과 모션벡터)  (0) 2021.03.01
728x90

딥러닝 part 강의를 들었습니다

음.. tensor 버전을 오래전 버전으로 사용하셨더라고요 

코드 방식도 옛날 버전으로 작성하셨다고 해서 봤는데 비슷하면서도 조금 이해 안 가는 부분도 있었어요

 

그래서 학습하는 부분은 강의로만 보면서 따라 갔고 

따로 직접 돌려보진 않았어요 

 

오늘 중점적으로 배운 내용은 학습된 모델을 가지고 opencv에서 어떻게 사용하는지에 대한 내용이었습니다

생각보다 간단해서 좋았어요

적용하기도 편하고 이해하는 것도 어렵지 않았습니다

다만 한글 손글씨 실습 내용은 좀 복잡했습니다

 

손글씨 데이터를 만들기 위해서 폰트를 다운로드하여서 활용한다는 점이 꽤 신박하다고 생각했어요

이 실습에서는 글씨의 모양 자체를 변형해서 학습시키진 않았고 단지 데이터 양만 늘려서 사용하셨더라고요

 

이걸 보면서 생각한 게

한 글자 자체에 히스토그램 분포도 있는 것처럼 글자 자체를 구성하는 정규분포가 있다면 굳이 글자를 일일이 변형해서 사용하지 않아도 쉽게 데이터를 좀 더 다양하게 얻을 수 있지 않을까 라는 생각이 들더라고요 

 

아무튼 오늘은 학습 코드는 제외한 내용을 업로드했습니다 

그래서 다른 날보다는 확실히 내용이 적습니다! 

 

내일이면 opencv 강의도 완강하는데 처음부터 복습을 쭈~욱 해야 하지 않나 생각하고 있어요

opencv를 이용해서 프로젝트도 진행하고 싶은데 아직.. 음;; 시간이 꽤 많이 걸릴 것 같고.. 뭔가 가이드가 없으니까 

길 잃은 얘처럼 헤매는 것 같네요 ㅎㅎ 

2021/03/04 - [실습 note] - OpenCV_11(딥러닝)

 

OpenCV_11(딥러닝)

OpenCV DNN(MNIST) import sys import numpy as np import cv2 oldx, oldy = -1, -1 def on_mouse(event, x, y, flags, _): global oldx, oldy if event == cv2.EVENT_LBUTTONDOWN: oldx, oldy = x, y elif event..

ghdrldud329.tistory.com

 

728x90

'Data Diary' 카테고리의 다른 글

2021-03-06(OpenCV_13)  (0) 2021.03.06
2021-03-05(OpenCV_12)  (0) 2021.03.05
2021-03-03(OpenCV_10)  (0) 2021.03.03
2021-03-01(OpenCV_9)  (0) 2021.03.01
2021-02-26(OpenCV_8)  (0) 2021.02.26
728x90

 

OpenCV DNN(MNIST)

import sys
import numpy as np
import cv2


oldx, oldy = -1, -1


def on_mouse(event, x, y, flags, _):
    global oldx, oldy

    if event == cv2.EVENT_LBUTTONDOWN:
        oldx, oldy = x, y

    elif event == cv2.EVENT_LBUTTONUP:
        oldx, oldy = -1, -1

    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            cv2.line(img, (oldx, oldy), (x, y), (255, 255, 255), 40, cv2.LINE_AA)
            oldx, oldy = x, y
            cv2.imshow('img', img)

def norm_digit(img):
	m = cv2.moments(img)
    cx = m['m10'] / m['m00']
    cy = m['m01'] / m['m00']
    h,w = img.shape[:2]
    aff = np.array([[1,0, w/2-cx], [0,1,h/2-cy]], dtype = np.float32)
    dst = cv2.warpAffine(img, aff, (0,0))
    return dst

net = cv2.dnn.readNet('mnist_cnn.pb')

if net.empty():
    print('Network load failed!')
    sys.exit()

img = np.zeros((400, 400), np.uint8) #숫자를 그릴 판

cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)

while True:
    c = cv2.waitKey()

    if c == 27:
        break
    elif c == ord(' '):
        #직접 그린 숫자 400*400짜리 이미지를 blob이라는 객체로 변환
        #blob은 4차원 형식의 ndarray (N,C,H,W)
        #학습 시, 학습데이터 픽셀값을 0~1까지 정규화하여 학습했으므로 1/255.을 넣어서 똑같이 정규화 해준다
        #학습 데이터 mnist 크기그 28*28이였으므로 똑같은 크기인 28*28 resize 시행 
        #내가 그린 숫자를 가운데에 위치시켜 놓고 진행: norm_digit
        blob = cv2.dnn.blobFromImage(norm_digit(img), 1/255., (28, 28))
        net.setInput(blob)

        '''
        prob: (1,10) 10개의 elemnet가 있고,
        확률이 최대값인 element의 인덱스값 = 모델이 인식한 숫자
        '''

        prob = net.forward()
        print('prob',prob)
        #최대값인 확률값과 그 위치를 반환
        _, maxVal, _, maxLoc = cv2.minMaxLoc(prob)
        print('maxLoc',maxLoc)

        digit = maxLoc[0] #최대값 성분의 index값 

        print(f'{digit} ({maxVal * 100:4.2f}%)')

        img.fill(0)
        cv2.imshow('img', img)

cv2.destroyAllWindows()

 

OpenCV DNN_googlenet

import sys
import numpy as np
import cv2


# 입력 영상 불러오기

filename = 'space_shuttle.jpg' #우주선

if len(sys.argv) > 1: #명령창에서 py명[0], 입력영상[1] 쓰면 같이 실행되게끔 하는 ㅋ코드
    filename = sys.argv[1]

img = cv2.imread(filename)

if img is None:
    print('Image load failed!')
    sys.exit()

# 네트워크 불러오기

# Caffe
# model = 'googlenet/bvlc_googlenet.caffemodel'
# config = 'googlenet/deploy.prototxt'

# ONNX
model = 'googlenet/googlenet-9.onnx'
config = '' #ONNX에서는 config 필요 없음

net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Network load failed!')
    sys.exit()

# 클래스 이름 불러오기
classNames = None
with open('googlenet/classification_classes_ILSVRC2012.txt', 'rt') as f:
    classNames = f.read().rstrip('\n').split('\n') #공백 단위로 제거와 분리 진행

# 추론
#1: 학습 시 0~255를 사용했다는 의미
#(104, 117, 123): BGR평균값? 
blob = cv2.dnn.blobFromImage(img, 1, (224, 224), (104, 117, 123))
net.setInput(blob)
prob = net.forward()

# 추론 결과 확인 & 화면 출력

out = prob.flatten()
classId = np.argmax(out) #가장 큰 값이 있는 위치 찾기
confidence = out[classId] #가장 큰 확률 값 나타내기

text = f'{classNames[classId]} ({confidence * 100:4.2f}%)'
cv2.putText(img, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)

cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()

 

 

 

 

 

 

 

 

 

728x90

'실습 note' 카테고리의 다른 글

제조 공정 불량 검출 실습  (0) 2021.03.11
OpenCV_12(딥러닝2)  (0) 2021.03.05
OpenCV_10(머신러닝)  (0) 2021.03.03
OpenCV_9(객체 추적과 모션벡터)  (0) 2021.03.01
OpenCV_8(특징점 검출&매칭)  (0) 2021.02.26
728x90

진도가 나갈수록 난이도가 올라가서 

강의 9개 분량의 진도와 복습만 하루가 걸리다 못해 밀리고 있습니다 ㅎㅎㅎ 

난이도가 올라감에따라 제 한숨도 늘어가고 있답니다

 

오늘 복습중의 이해가 부족한 부분이

def norm_digit(img): #img: 부분영상 20*20
    m = cv2.moments(img)

    #cx,cy:무게중심좌표
    cx = m['m10'] / m['m00'] #글씨부분 x좌표를 모두 더한 픽셀/전체 픽셀
    cy = m['m01'] / m['m00'] #글씨부분 y좌표를 모두 더한 픽셀/전체 픽셀(레이블링 원리 보기)
    h, w = img.shape[:2]

    #aff(2행 3열)->어파인의 (2,3)행렬 개념 보기
    aff = np.array([[1, 0, w/2 - cx], [0, 1, h/2 - cy]], dtype=np.float32) #공부요망
    dst = cv2.warpAffine(img, aff, (0, 0))
    return dst

여기에서 aff부분입니다 

글자를 중심위치로 정규화 하기 위한 코드인데요

아직 낯설인지느 몰라도 aff 부분의 w/2 -cx, h/2-cy를 제대로 이해하지 못하고 있어요

중심위치로 가야하니까 가로세로크기에서 반을 나눈건 알겠지만 굳이 cx,cy를 빼야 하는 이유를 찾지 못했습니다

 

그런데 왠지 이 문제가 상식적인 선에서 해결되는 문제인것 같다는 예감이 들어요 

당연히 이렇게 해야 중심위치에 가야하는건데 나만 모르는 느낌이랄까

 

아무튼 좋지 않은 기분인건 확실합니다

moment 함수도 처음 봤는데 알아보니까 호락호락한 놈이 아닌것같더라구요

곳곳이 지뢰밭이라서 정성스럽게 진도를 나가다 보니까 복습할 내용이 밀리는게 당연하다고 또 생각이 듭니다

 

여담이지만 요즘 눈 건강이 조금 나빠짐을 느끼고 있습니다 

저번주 부터 점차 그런것같은데 이젠 대놓고 뻐근함을 느끼고 있어요

집중도 전처럼 좋지 못한것 같고 .. 흠... 요즘생각이 많아서 그런것같습니다

 

이 블로그 목적은 정보공유도 있지만 제 꿈을 이뤄나가는 날날들을 기록하는데에 큰 의미를 두고 있습니다

그런데, 그 꿈이 큰 장벽으로 느껴져서 동기가 약해지고 좌절감이 드는것도 사실이네요 ㅠ

쉬워서 도전한게 아니었으니까 

희망을 가지고 도줜~!  

 

2021/03/03 - [실습 note] - OpenCV_10(머신러닝)

 

OpenCV_10(머신러닝)

knn ### KNN import numpy as np import cv2 #트랙바 def on_k_changed(pos): global k_value k_value = pos if k_value < 1: k_value = 1 trainAndDisplay() def addPoint(x, y, c): train.append([x, y]) #x,y를..

ghdrldud329.tistory.com

 

728x90

'Data Diary' 카테고리의 다른 글

2021-03-05(OpenCV_12)  (0) 2021.03.05
2021-03-04(OpenCV_11)  (0) 2021.03.04
2021-03-01(OpenCV_9)  (0) 2021.03.01
2021-02-26(OpenCV_8)  (0) 2021.02.26
2021-02-25(OpenCV_7)  (0) 2021.02.25
728x90

2021/03/03 - [기록 note] - 2021-03-03(OpenCV_10)

 

2021-03-03(OpenCV_10)

진도가 나갈수록 난이도가 올라가서 강의 9개 분량의 진도와 복습만 하루가 걸리다 못해 밀리고 있습니다 ㅎㅎㅎ 난이도가 올라감에따라 제 한숨도 늘어가고 있답니다 오늘 복습중의 이해가 부

ghdrldud329.tistory.com

knn

### KNN

import numpy as np
import cv2

#트랙바 
def on_k_changed(pos): 
    global k_value

    k_value = pos
    if k_value < 1:
        k_value = 1

    trainAndDisplay()


def addPoint(x, y, c):
    train.append([x, y]) #x,y를 리스트로 묶어서 train에 추가
    label.append([c]) 


def trainAndDisplay():
    trainData = np.array(train, dtype=np.float32) #ndarray로 변환(float 타입)
    labelData = np.array(label, dtype=np.int32)

    #ROW_SAMPLE: 데이터 형태가 한 행에 들어간다는 의미
    knn.train(trainData, cv2.ml.ROW_SAMPLE, labelData) #90개 점
    #주의
    #trainData shape = (90,2), dtype=float32
    #labelData shape = (90,1) dtype=int32

    h, w = img.shape[:2]

    #각각의 좌표 표현을 위한 아래의 for loop는 시간이 오래걸림 
    for y in range(h):
        for x in range(w):
            #img(500*500)영상의 각각의 점들을 sample에 넣고 예측, 각 한 점씩 예측한다
            #(1,0),(2,0),....,(499,499)
            sample = np.array([[x, y]]).astype(np.float32) #샘플 하나짜리, (x,y)

            ret, result, _, _ = knn.findNearest(sample, k_value) #예측 코드
            # print('ret',ret)
            # print('result',result)

            '''
            ret: 예측한 클래스 정보 들어있음(0 or 1 or 2)
            result: 좌표를 하나 예측했으므로 1*1인 레이블 행렬을 반환
            현재 점이 하나이기 때문에 ret 값과 result의 (0,0) 값은 같다
            ret = result[0,0]
            '''
            ret = int(ret)
            if ret == 0:
                img[y, x] = (128, 128, 255) #0번클래스면 빨간색에 근접한 색
            elif ret == 1:
                img[y, x] = (128, 255, 128) #1번 녹색
            elif ret == 2:
                img[y, x] = (255, 128, 128) #2번 파란색

    #제너레이션된 점(3시그마)들을 화면에 보여주는 코드
    for i in range(len(train)):
        x, y = train[i]
        l = label[i][0]

        if l == 0:
            cv2.circle(img, (x, y), 5, (0, 0, 128), -1, cv2.LINE_AA)
        elif l == 1:
            cv2.circle(img, (x, y), 5, (0, 128, 0), -1, cv2.LINE_AA)
        elif l == 2:
            cv2.circle(img, (x, y), 5, (128, 0, 0), -1, cv2.LINE_AA)

    cv2.imshow('knn', img)

'''
2차원 평면에 랜덤하게 점을 찍은 후 3개의 클래스로 구분
'''
# 학습 데이터 & 레이블
train = [] #점들의 좌표
label = [] 

k_value = 1
img = np.full((500, 500, 3), 255, np.uint8)
knn = cv2.ml.KNearest_create()

# 랜덤 데이터 생성
NUM = 30
rn = np.zeros((NUM, 2), np.int32) #결과를 받을 행렬 생성, 30행2열, 60개요소 

# (150, 150) 근방의 점은 0번 클래스로 설정
cv2.randn(rn, 0, 50) #가우시안 랜덤, 평균: 0, 표쥰편차:50
for i in range(NUM):
    #addPoint(x,y,해당 점의 클래스)
    addPoint(rn[i, 0] + 150, rn[i, 1] + 150, 0) 

# (350, 150) 근방의 점은 1번 클래스로 설정
cv2.randn(rn, 0, 50)
for i in range(NUM):
    addPoint(rn[i, 0] + 350, rn[i, 1] + 150, 1) 

# (250, 400) 근방의 점은 2번 클래스로 설정
cv2.randn(rn, 0, 70)
for i in range(NUM):
    addPoint(rn[i, 0] + 250, rn[i, 1] + 400, 2) 

# 영상 출력 창 생성 & 트랙바 생성
cv2.namedWindow('knn')
cv2.createTrackbar('k_value', 'knn', 1, 5, on_k_changed)

# KNN 결과 출력
trainAndDisplay()

cv2.waitKey()
cv2.destroyAllWindows()

 

knn_digit

### knndigit

import sys
import numpy as np
import cv2


oldx, oldy = -1, -1


#직접 숫자를 그리는 프로그램
def on_mouse(event, x, y, flags, _):
    global oldx, oldy

    if event == cv2.EVENT_LBUTTONDOWN:
        oldx, oldy = x, y

    elif event == cv2.EVENT_LBUTTONUP:
        oldx, oldy = -1, -1

    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            cv2.line(img, (oldx, oldy), (x, y), (255, 255, 255), 40, cv2.LINE_AA)
            oldx, oldy = x, y
            # print('oldx',oldx)
            # print('oldy',oldx)
            cv2.imshow('img', img)


# 학습 & 레이블 행렬 생성

digits = cv2.imread('digits.png', cv2.IMREAD_GRAYSCALE)

if digits is None:
    print('Image load failed!')
    sys.exit()

#세로로 50개 숫자 이미지가 있다.
#0~9까지 각각 5개 세로줄, 가로는 2000씩
#0:(5,2000)
h, w = digits.shape[:2] #w: 2000, h:1000

#각각의 숫자를 부분영상으로 짤라내는코드 

#np.hsplit(row, w//20): 숫자하나에 20*20짜리 영상이므로 2000을 20으로 나눈다
#np.vsplit(digits, h//20):#h//20:50개로 분할=> 0은 0끼리, 1은1끼리 분할
#가로로 100개, 세로로 50개
#세로 50개 안에는 0이 5개, 1이 5개, 2가 5개 ~ 9가 5개 총 50개
cell = [np.hsplit(row, w//20) for row in np.vsplit(digits, h//20)] #과자를 짜르듯이 세로로 먼저 20간격씩 자르고 가로로 20씩 자른다
cells = np.array(cell) #리스트를 ndarray

#20*20을 400으로 변환
#행이 몇개든 관심없고 일단 가로로 400개씩 나열하는게 먼저
train_images = cells.reshape(-1, 400).astype(np.float32) #(5000,400) dtype=float32

#0이 500개있으므로 이에 맞는 레이블을 repeat를 통해 만든다
train_labels = np.repeat(np.arange(10), len(train_images)/10) #(5000,1)

# KNN 학습

knn = cv2.ml.KNearest_create()
knn.train(train_images, cv2.ml.ROW_SAMPLE, train_labels)

# 사용자 입력 영상에 대해 예측
img = np.zeros((400, 400), np.uint8)

cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)

while True:
    key = cv2.waitKey()

    if key == 27:
        break
    elif key == ord(' '):
        #400*400이미지를 20*20으로 줄인다
        test_image = cv2.resize(img, (20, 20), interpolation=cv2.INTER_AREA)
        
        #1행400열짜리로 만들고 타입변경한다
        test_image = test_image.reshape(-1, 400).astype(np.float32)

        ret, _, _, _ = knn.findNearest(test_image, 5)
        print(int(ret))

        img.fill(0) # 그려져 있는 숫자영상을 다시 검정색으로 초기화
        cv2.imshow('img', img)

cv2.destroyAllWindows()

 

SVM

import sys
import numpy as np
import cv2


trains = np.array([[150, 200], [200, 250], #0
                   [100, 250], [150, 300], #0
                   [350, 100], [400, 200], #1
                   [400, 300], [350, 400]], dtype=np.float32) #1
labels = np.array([0, 0, 0, 0, 1, 1, 1, 1])

svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC) 
# svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setKernel(cv2.ml.SVM_RBF)

#trainAuto대신 train으로 변경후  C,Gamma를 따로 셋팅하면 같은결과가 나온다
#감마값을 키울수록 샘플에 의존적인 형태가 나온다
svm.setC(2.5)
svm.setGamma(0.00001)

svm.train(trains, cv2.ml.ROW_SAMPLE, labels) #다양한 C,gamma 값을 테스트 한다 
# svm.trainAuto(trains, cv2.ml.ROW_SAMPLE, labels)
print('C:', svm.getC())
print('Gamma:', svm.getGamma())

#시각화 위한코드
w, h = 500, 500
img = np.zeros((h, w, 3), dtype=np.uint8)

for y in range(h):
    for x in range(w):
        test = np.array([[x, y]], dtype=np.float32)
        _, res = svm.predict(test)
        ret = int(res[0, 0])

        if ret == 0:
            img[y, x] = (128, 128, 255)  # Red
        else:
            img[y, x] = (128, 255, 128)  # Green

color = [(0, 0, 128), (0, 128, 0)]

for i in range(trains.shape[0]):
    x = int(trains[i, 0])
    y = int(trains[i, 1])
    l = labels[i]

    cv2.circle(img, (x, y), 5, color[l], -1, cv2.LINE_AA)

cv2.imshow('svm', img)
cv2.waitKey()
cv2.destroyAllWindows()

 

HOG&SVM

import sys
import numpy as np
import cv2


oldx, oldy = -1, -1

#학습을 하고난 후 400*400 img가 뜬다->숫자그리기
def on_mouse(event, x, y, flags, _):
    global oldx, oldy

    if event == cv2.EVENT_LBUTTONDOWN:
        oldx, oldy = x, y

    elif event == cv2.EVENT_LBUTTONUP:
        oldx, oldy = -1, -1

    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            cv2.line(img, (oldx, oldy), (x, y), (255, 255, 255), 40, cv2.LINE_AA)
            oldx, oldy = x, y
            cv2.imshow('img', img)

#정규화_무게중심을 중간으로 이동(치우침을 제거)
#학습,테스트 할때 모두사용
def norm_digit(img): #img: 부분영상 20*20
    m = cv2.moments(img)

    #cx,cy:무게중심좌표
    cx = m['m10'] / m['m00'] #글씨부분 x좌표를 모두 더한 픽셀/전체 픽셀
    cy = m['m01'] / m['m00'] #글씨부분 y좌표를 모두 더한 픽셀/전체 픽셀(레이블링 원리 보기)
    h, w = img.shape[:2]

    #aff(2행 3열)->어파인의 (2,3)행렬 개념 보기
    aff = np.array([[1, 0, w/2 - cx], [0, 1, h/2 - cy]], dtype=np.float32) #공부요망
    dst = cv2.warpAffine(img, aff, (0, 0))
    return dst


# 학습 데이터 & 레이블 행렬 생성

digits = cv2.imread('digits.png', cv2.IMREAD_GRAYSCALE)

if digits is None:
    print('Image load failed!')
    sys.exit()

h, w = digits.shape[:2]

#p.500 참고
#검출 윈도우 크기 (20,20), 블럭의 크기:(10,10), 셀크기:(5,5), 셀이동크기(stride)=(5,5) 즉,셀단위로 이동, bin=9개
hog = cv2.HOGDescriptor((20, 20), (10, 10), (5, 5), (5, 5), 9)
print('Descriptor Size:', hog.getDescriptorSize()) #블록하나에서의 히스토그램은 4*9=36개, 36*9=324차원의 특징벡터 

cells = [np.hsplit(row, w//20) for row in np.vsplit(digits, h//20)]
cell1 = np.array(cells) #(50,100,20,20) 
# print('cell1',cell1.shape)

cells = cell1.reshape(-1, 20, 20)  # shape=(5000, 20, 20) 20*20짜리가 5000개

#각각의 20*20짜리의 서브이미지에 대해서 호그 특징벡터를 추출
desc = []
for img in cells:
    img = norm_digit(img) #정규화
    desc.append(hog.compute(img)) #(324,1)

train_desc = np.array(desc) #desc: (324,1)이 5000개 있는 리스트, 따라서 train_desc: (5000,324,1)

#(5000,324,1)중에 1은 필요가 없어서 squeeze()를 사용하여 없앰
#squeeze는 차원 중 사이즈가 1인 것을 찾아 스칼라값으로 바꿔 해당 차원을 제거한다. ex)2차원을 벡터로
train_desc = train_desc.squeeze().astype(np.float32) #(5000,324)인 train_desc 타입은 float32로 넣어준다
train_labels = np.repeat(np.arange(10), len(train_desc)/10)

print('train_desc.shape',train_desc.shape)
print('train_labels.shape',train_labels.shape)

# SVM 학습

svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_RBF)
svm.setC(2.5)
svm.setGamma(0.50625)

svm.train(train_desc, cv2.ml.ROW_SAMPLE, train_labels)
#svm.save('svmdigits.yml')

# 사용자 입력 영상에 대해 예측

#마우스로 그릴수 있도록하는 인터페이스 80~83
img = np.zeros((400, 400), np.uint8)

cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)

while True:
    key = cv2.waitKey()

    if key == 27:
        break
    elif key == ord(' '):
        test_image = cv2.resize(img, (20, 20), interpolation=cv2.INTER_AREA)
        test_image = norm_digit(test_image)
        test_desc = hog.compute(test_image).T #(324,1)->(1,324), train과 같은 형식으로

        _, res = svm.predict(test_desc) #predict에 들어갈 형태는 (1행,D열)
        print(int(res[0, 0]))

        img.fill(0)
        cv2.imshow('img', img)

cv2.destroyAllWindows()

 

HOG&SVM2

import sys
import numpy as np
import cv2


# 숫자 영상을 20x20 크기 안에 적당히 들어가도록 리사이즈
def norm_img(img): #img는 부분영상
    h, w = img.shape[:2]
    print('h:',h, 'w:',w) #영상마다 size 다 다름

    img = ~img #반전 : 짤라낸 원본이미지는 반전이 필요한 이미지이다.
    blr = cv2.GaussianBlur(img, (0, 0), 2) #노이즈 제거
    
    #14픽셀을 h로 나눔
    '''
    원래는 20./h 해서 resize크기를 세로 20으로 만드는게 맞지만
    위,아래 픽셀을 3 픽셀씩 여유를 주기 위해서 숫자가 차지할 자리를 14픽셀로 설정함
    '''
    sf = 14. / h  # scale factor. 위/아래 3픽셀씩 여백 고려. 20-6=14
    if w > h:
        sf = 14. / w

    #가로세로 비율을 맞추기 위해 같은 스케일팩터 적용
    img2 = cv2.resize(img, (0, 0), fx=sf, fy=sf, interpolation=cv2.INTER_AREA)
    print('img2.shape',img2.shape)
    h2, w2 = img2.shape[:2] 
    print('h2:',h2, 'w2:',w2)

    #정 가운데 좌표를 잡기위한 시작점 포인트 설정 
    a = (20 - w2) // 2
    b = (20 - h2) // 2
    # print('가로','세로','(',a,',',b,')')
    
    dst = np.zeros((20, 20), dtype=np.uint8) 

    #dst2를 그냥쓰는게 아니라 dst 가운데에 dst2를 카피한다. -> 모두 같은 사이즈를 얻게됨
    dst[b:b+h2, a:a+w2] = img2[:, :] #img2모든 걸 copy
    print('b:b+h2, a:a+w2:',b,':',b+h2, a,':',a+w2)
    cv2.imshow('img',img)
    # cv2.imshow('dst',dst)
    return dst


# 입력 필기체 숫자 이미지 불러오기
src = cv2.imread('handwritten2.png')

if src is None:
    print('Image load failed!')
    sys.exit()

# HOG 객체 생성
hog = cv2.HOGDescriptor((20, 20), (10, 10), (5, 5), (5, 5), 9)

# 미리 학습된 SVM 데이터 불러오기
svm = cv2.ml.SVM_load('svmdigits.yml')

# 이진화 & 레이블링
src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

#src: 흰색 배경에 검정 글 ->INV 반전 시킨다, opencv에서의 객체는 흰색 픽셀이다
_, src_bin = cv2.threshold(src_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)

#이진화된 영상을 레이블링->바운딩 박스 추출
cnt, _, stats, _ = cv2.connectedComponentsWithStats(src_bin)

dst = src.copy()

for i in range(1, cnt):
    x, y, w, h, s = stats[i]

    if s < 100: #3.141592 에서 . 을 삭제하기 위함
        continue

    # 각각의 숫자 부분 영상을 정규화한 후 HOG&SVM 숫자 인식
    '''
    필기체 중 1의 바운딩 박스는 세로로 긴 박스일것이다. 이 박스를 20*20으로 resize해서
    정 가운데에 이쁘게 오게끔 만드는게 목적->norm_img
    '''
    digit = norm_img(src_gray[y:y+h, x:x+w]) #객체를 인식한 바운딩 박스를 사용해서 짤라내기!!
    test_desc = hog.compute(digit).T 
    # print('test_desc.shape',test_desc.shape)
    _, res = svm.predict(test_desc)
 
    # HOG&SVM 숫자 인식 결과 출력
    cv2.rectangle(dst, (x, y, w, h), (0, 0, 255))
    cv2.putText(dst, str(int(res[0, 0])), (x, y - 5),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)

cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

 

Kmeans

import sys
import numpy as np
import cv2


# 입력 영상 불러오기
src = cv2.imread('flowers.jpg')

if src is None:
    print('Image load failed')
    sys.exit()

# 차원 변환 & np.float32 자료형 변환
data = src.reshape((-1, 3)).astype(np.float32) #data.shape:(세로*가로,3) 이차원형태

# K-means 알고리즘
#최대 10번 반복하고, 1픽셀 이하로 움직임이 멈추면 종료
criteria = (cv2.TERM_CRITERIA_EPS|cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

for K in range(2, 9):
    print('K:', K)
    #label: 각각의 점이 몇번 클래스 인지 알려줌(몇번 군집에 속하는가)
    #label shape: (307200,1) = 전체 픽셀 개수
    #그 군집의 중심점 좌표가 center
    ret, label, center = cv2.kmeans(data, K, None, criteria, 10,cv2.KMEANS_RANDOM_CENTERS)
    
    # 군집화 결과를 이용하여 출력 영상 생성
    center = np.uint8(center)


    dst = center[label.flatten()]  # 각 픽셀을 K개 군집 중심 색상으로 치환, 2차원->1차원
    print('center',center)
    print('center.shape',center.shape)
    # print('dst',dst)
    print('dst.shape ',dst.shape)
    print('label',label.flatten())
    #dst를 그냥쓰게 되면 세로가 307200이므로 입력영상과 같게 reshape
    dst = dst.reshape((src.shape)) 

    cv2.imshow('src', src)
    cv2.imshow('dst', dst)
    cv2.waitKey()

cv2.destroyAllWindows()
728x90

'실습 note' 카테고리의 다른 글

OpenCV_12(딥러닝2)  (0) 2021.03.05
OpenCV_11(딥러닝)  (0) 2021.03.04
OpenCV_9(객체 추적과 모션벡터)  (0) 2021.03.01
OpenCV_8(특징점 검출&매칭)  (0) 2021.02.26
OpenCV_7(영상분할&객체검출)  (0) 2021.02.25
728x90

오늘은 객체 추적/모션벡터 실습을 했습니다. 오늘 배운 내용중 이해하기 조금 힘든 개념이 있었습니다

특히, MOG라는 것이 각 픽셀에 대해 MOG 확률 모델을 설정하여 배경과 전경을 구분한다고 하는데, 강의 설명으로는 부족해서 구글링을 했지만 제가 이해 할만한 내용은 아직 찾지 못했습니다 ㅠ

이 부분은 지속적으로 검색해 봐야 할것같습니다

 

이외에도 실습 코드 중에서 조금 생소한것들이 군데군데 박혀 있어서 제대로 복습하고 넘어가야 할것같습니다

이번주면 강의와 실습이 모두 끝날텐데 어떤식으로 프로젝트를 해야할까 

아니면 처음부터 복습을 할까 많이 고민됩니다

 

벌써 3월달인데 

시간이 갈수록 취업 압박을 받는건 어쩔수가 없는 것같아요

불안한 마음잡고 제가 할수 있는 일에 집중하도록 노력해야 할것같습니다 :) 

 

2021/03/01 - [실습 note] - OpenCV_9(객체 추적과 모션벡터)

 

OpenCV_9(객체 추적과 모션벡터)

### 차분영상 #첫번째 영상 - frame들 import sys import numpy as np import cv2 # 비디오 파일 열기 cap = cv2.VideoCapture('PETS2000.avi') if not cap.isOpened(): print('Video open failed!') sys.exit() #..

ghdrldud329.tistory.com

 

 

728x90

'Data Diary' 카테고리의 다른 글

2021-03-04(OpenCV_11)  (0) 2021.03.04
2021-03-03(OpenCV_10)  (0) 2021.03.03
2021-02-26(OpenCV_8)  (0) 2021.02.26
2021-02-25(OpenCV_7)  (0) 2021.02.25
2021-02-24(OpenCV_6)  (0) 2021.02.24
728x90

 

 

### 차분영상 

#첫번째 영상 - frame들

import sys
import numpy as np
import cv2


# 비디오 파일 열기
cap = cv2.VideoCapture('PETS2000.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

#첫번째 프레임을 배경영상으로 등록
#컬러로 구해도 되지만 현재는 굳이 컬러로 할 필요가 없고, 연산 속도를 올리기 위해서 gray로 변환
_,back = cap.read()
back = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)

#노이즈 제거위한 가우시안
#ksize= (0,0), 시그마 1 
back =cv2.GaussianBlur(back, (0,0), 1)

while True:
    ret, frame = cap.read() 

    if not ret:
        break
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    #블러처리
    frame =cv2.GaussianBlur(frame, (0,0), 1)
    
    #단순히 뺄셈이 아닌, 뺄셈 후 절대값을 넣어준다
    diff=cv2.absdiff(back, frame)

    #차이값이 30이상이면 255로 만들고 그게 아니면 0으로 만들기
    _,diff=cv2.threshold(diff,30,255, cv2.THRESH_BINARY)

    cv2.imshow('frame',frame)
    cv2.imshow('diff',diff)
    if cv2.waitKey(30)==27:
        break

    '''
    #블러를 하기 전 영상결과#
    결과 영상에서는 같은 물체지만 선에따라 하얀 점들이 반짝인다. 
    빛의 반사라든지 여러 요인으로 인해 튀는 값들이다. (노이즈)
    모폴로지 열기 연산 적용가능하지만 이번실습에서는 가우시안 블러를 이용한다
    '''
    '''
    흰색객체를 레이블링을 통해서 객체의 위치와 크기를 판단 한 후, 해당 위치에 바운딩 박스 그리면
    침입자 프로그램 만들수있다
    '''
cap.release()
cv2.destroyAllWindows()

 

## 차분영상2

import sys
import numpy as np
import cv2


# 비디오 파일 열기
cap = cv2.VideoCapture('PETS2000.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 배경 영상 등록
ret, back = cap.read()

if not ret:
    print('Background image registration failed!')
    sys.exit()

back = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)
back = cv2.GaussianBlur(back, (0, 0), 1.0)

# 비디오 매 프레임 처리
while True:
    ret, frame = cap.read()

    if not ret:
        break

    #그레이 변환 
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    #블러처리
    gray = cv2.GaussianBlur(gray, (0, 0), 1.0)

    # 차영상 구하기 & 이진화
    diff = cv2.absdiff(gray, back)

    #임계값 적용 후 레이블링
    _, diff = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)

    # 레이블링을 이용하여 바운딩 박스 표시
    cnt, _, stats, _ = cv2.connectedComponentsWithStats(diff)

    for i in range(1, cnt):
        #s : 객체 픽셀 사이즈
        x, y, w, h, s = stats[i]

        if s < 100:
            continue

        #본래 영상 frame에다가 박스 그리기
        cv2.rectangle(frame, (x, y, w, h), (0, 0, 255), 2)

    cv2.imshow('frame', frame)
    cv2.imshow('diff', diff)

    if cv2.waitKey(30) == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

### 이동평균 배경차분영상

import sys
import numpy as np
import cv2


# 비디오 파일 열기
cap = cv2.VideoCapture('PETS2000.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 첫번째 프레임을 배경 영상 등록
ret, back = cap.read()

if not ret:
    print('Background image registration failed!')
    sys.exit()

# back: uint8 배경, fback: float32 배경
back = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)

#노이즈 제거 위한 블러처리
back = cv2.GaussianBlur(back, (0, 0), 1.0)
print('back',back)
#업데이트는 미세한 값을 다루기 때문에 float 타입으로 변환 후 진행한다
fback = back.astype(np.float32)

# 비디오 매 프레임 처리
while True:
    ret, frame = cap.read()

    if not ret:
        break

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (0, 0), 1.0)

    # fback: float32, back: uint8 배경
    #fback(dst): dst가 입력에도 있고 출력에도 있을경우엔 dst를 인자로 줘야한다. 출력으로 받으면 안된다
    # 알파값:0.01(gray적용), 0.99(fback적용)
    cv2.accumulateWeighted(gray, fback, 0.01)

    #absdiff는 두개의 입력영상 타입이 같아야 한다
    back = fback.astype(np.uint8)
    diff = cv2.absdiff(gray, back)
    _, diff = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)

    # 레이블링을 이용하여 바운딩 박스 표시
    cnt, _, stats, _ = cv2.connectedComponentsWithStats(diff)

    for i in range(1, cnt):
        x, y, w, h, s = stats[i]

        if s < 100:
            continue

        cv2.rectangle(frame, (x, y, w, h), (0, 0, 255), 2)

    cv2.imshow('frame', frame)
    cv2.imshow('diff', diff)
    cv2.imshow('back', back)

    if cv2.waitKey(30) == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

### MOG 추적

import sys
import numpy as np
import cv2


# 비디오 파일 열기
cap = cv2.VideoCapture('PETS2000.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 배경 차분 알고리즘 객체 생성

# history 기본값500: 과거 몇개의 프레임을 사용할건지 정함(기본값 500프레임)
# detectshadow: True(그림자 검출가능)
# bs = cv2.createBackgroundSubtractorMOG2() #MOG2 원리 이해x

bs = cv2.createBackgroundSubtractorKNN()

#그림자를 나타낸 회색이 없어지고 255로 처리됨
# bs.setDetectShadows(False) 

# 비디오 매 프레임 처리
while True:
    ret, frame = cap.read()

    if not ret:
        break

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    #apply 이용해서 현재프레임을 입력(다음 비디오 프레임)으로 넣어서 계속 업데이트
    #fgmask: 0또는 255, 그림자까지 포함한다면 0,128,255 세개의 값으로 구성된 마스크 
    fgmask = bs.apply(gray)
    back = bs.getBackgroundImage() #현재 배경영상이 어떻게 업데이트가 되는지 볼수 있는 함수

    # 레이블링을 이용하여 바운딩 박스 표시
    cnt, _, stats, _ = cv2.connectedComponentsWithStats(fgmask)

    for i in range(1, cnt):
        x, y, w, h, s = stats[i]

        if s < 80: #사각형 안 픽셀 수가 80보다 작으면 무시
            continue

        cv2.rectangle(frame, (x, y, w, h), (0, 0, 255), 2)

    cv2.imshow('frame', frame)
    cv2.imshow('back', back)
    cv2.imshow('fgmask', fgmask)

    if cv2.waitKey(20) == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

## 이동평균 추적

import sys
import numpy as np
import cv2


# 비디오 파일 열기
cap = cv2.VideoCapture('camshift.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 초기 사각형 영역: (x, y, w, h)
x, y, w, h = 135, 220, 100, 100 #귤 좌표 설정(ROI selector)
rc = (x, y, w, h)

ret, frame = cap.read()

if not ret:
    print('frame read failed!')
    sys.exit()

roi = frame[y:y+h, x:x+w]
roi_hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

# HS 히스토그램 계산
channels = [0, 1] #hue(색상), saturation(채도)
ranges = [0, 180, 0, 256] #hue:0~180, sat: 0~256 (255+1 1더해서 설정해야한다)
#귤이 위치한 좌표 위치에 대해서 히스토그램을 계산
#위 색상,채도 범위를 가졌을때의 히스토그램을 계산
#2차원 히스토그램: 축이 2개이고, 각 축이 만나는 지점의 개수를 표현
hist = cv2.calcHist([roi_hsv], channels, None, [90, 128], ranges)

# Mean Shift 알고리즘 종료 기준
#iteration:10 
#정확도가 1 이하(이동크기가 1픽셀보다 작으면) 종료
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)

# 비디오 매 프레임 처리
while True:
    ret, frame = cap.read()

    if not ret:
        break

    # HS 히스토그램에 대한 역투영
    frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    #hist를 인자로 입력, 히스토그램 역투영 확률 영상을 반환
    #히스토그램 역투영:관심 영역의 히스토그램과 유사한 히스토그램을 갖는 영역을 찾아내는 기법
    #hist와 같은 컬러를 frame_hsv에서 찾아낸다
    backproj = cv2.calcBackProject([frame_hsv], channels, hist, ranges, 1)

    # Mean Shift
    # 본래는 입력이자 출력은 인자에만 입력해야하지만
    # rc가 튜플이라서 출력 표시를 해야 업데이트가 된다
    _, rc = cv2.meanShift(backproj, rc, term_crit)

    # 추적 결과 화면 출력
    cv2.rectangle(frame, rc, (0, 0, 255), 2)
    cv2.imshow('frame', frame)

    if cv2.waitKey(60) == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

### camshift 추적

#색상 정보 트래킹
import sys
import numpy as np
import cv2


# 비디오 파일 열기
cap = cv2.VideoCapture('camshift.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 초기 사각형 영역: (x, y, w, h)
x, y, w, h = 135, 220, 100, 100
rc = (x, y, w, h)

ret, frame = cap.read()

if not ret:
    print('frame read failed!')
    sys.exit()

roi = frame[y:y+h, x:x+w]
roi_hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) #원색을 추적할때는 HSV가 유리하다 왜?

# HS 히스토그램 계산
channels = [0, 1]
ranges = [0, 180, 0, 256]
hist = cv2.calcHist([roi_hsv], channels, None, [90, 128], ranges)

# CamShift 알고리즘 종료 기준
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)

# 비디오 매 프레임 처리
while True:
    ret, frame = cap.read()

    if not ret:
        break

    # HS 히스토그램에 대한 역투영
    frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    backproj = cv2.calcBackProject([frame_hsv], channels, hist, ranges, 1)

    # CamShift
    # return 값은 retval, window 인데  retval은 교재에 나와있는 것처럼 복잡한 튜플 형식이며
    # 이값을 이용해서 사각형을 회전된 사각형으로 바꿀수 있다
    # probImage=>backproj 확률에 대한 영상 즉, 점들의 분포가 어떻게 되어가고 있는지를 명시해야하는데
    # 여기서는 히스토그램의 역투영을 이용함, 혹은 데이터 분포를 표현 할수 있는 다른 방법을 적용시킬수 있다.(ndarray형태로)
    ret, rc = cv2.CamShift(backproj, rc, term_crit)

    # 추적 결과 화면 출력
    cv2.rectangle(frame, rc, (0, 0, 255), 2)
    #타원그리는 함수
    cv2.ellipse(frame, ret, (0, 255, 0), 2) #회전된 사각형에 내접하는 타원을 그려준다
    cv2.imshow('frame', frame)

    if cv2.waitKey(60) == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

### Optical Flow

import sys
import numpy as np
import cv2

#optical Flow 
'''
x방향으로의 이동속도
y방향으로의 이동속도
한 좌표가 다른 좌표로 이동했을때 overflow 미지수 두개 발생
어떤 N*N Window를 설정하면 객체가 이동하는 속도는 같으므로 N**2개 방정식이 생긴다
'''

src1 = cv2.imread('frame1.jpg')
src2 = cv2.imread('frame2.jpg')

if src1 is None or src2 is None:
    print('Image load failed!')
    sys.exit()

#컬러변환->goodFeaturesToTrack는 gray만 입력으로 받는다
gray1 = cv2.cvtColor(src1, cv2.COLOR_BGR2GRAY)

#코너점을 찾는 goodFeaturesToTrack함수
pt1 = cv2.goodFeaturesToTrack(gray1, 50, 0.01, 10)

#src1, src2 에서 움직임 정보를 찾아내서 pt1 코너점 좌표가 어디로 이동했는지 pt2에 정보가 담겨져 있다
#pt2(이동된 점의 좌표)는 None으로 입력하고 출력으로 받는다
pt2, status, err = cv2.calcOpticalFlowPyrLK(src1, src2, pt1, None)

dst = cv2.addWeighted(src1, 0.5, src2, 0.5, 0)

for i in range(pt2.shape[0]):
    #잘못된것은 표현 무시하고, 잘된 것만 표시하도록 해준다
    if status[i, 0] == 0: #status가 0인것은 무시, 움직이지 않고 제자리 인 좌표?
        continue
    print(pt1[i,0]) #x,y 코너점의 좌표
    cv2.circle(dst, tuple(pt1[i, 0]), 4, (0, 255, 255), 2, cv2.LINE_AA) #이동 전 좌표
    cv2.circle(dst, tuple(pt2[i, 0]), 4, (0, 0, 255), 2, cv2.LINE_AA) #이동 후 좌표
    cv2.arrowedLine(dst, tuple(pt1[i, 0]), tuple(pt2[i, 0]), (0, 255, 0), 2)

cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

 

728x90

'실습 note' 카테고리의 다른 글

OpenCV_11(딥러닝)  (0) 2021.03.04
OpenCV_10(머신러닝)  (0) 2021.03.03
OpenCV_8(특징점 검출&매칭)  (0) 2021.02.26
OpenCV_7(영상분할&객체검출)  (0) 2021.02.25
OpenCV_6(이진 영상 처리)  (0) 2021.02.24
728x90

오늘 특징점에 대해서 진도를 나갔습니다 

초반에 너무 졸려서 듣는 둥 마는 둥  

아무리 정신을 차려 보려고 해도, 10분을 자도 

영 공부가 안되더라구요 

 

게다가 특징점이니 .. keypoint니 해서 이게 저게같고 다 비슷한거같은데

너무 헷갈렸어요 복습이 부족해서 그런가 싶기도 해서 

내일도 원래 진도를 나갈 계획이였는데 주말이기도 하니까 

복습day로 바꿨습니다 

 

일단 강의 진도는 마치고 답답해서 운동좀 갓다오고 복습하면서

실습코드 분석하니까 이제야 흐름이 파악되더라구요 

사실 강의 진도도 다 못나갔어요 마지막 하나 최종실습 강의가 있는데 

더이상 진도 나가봤자 이해도 안되고 해서 처음부터 강의를 다시 돌려 봤었어요 

어.. 그래도 좀처럼 탁 트이는 느낌은 없었어요 

 

무튼 그래서 실습코드 따라 치면서 복습하니까 흐름파악이 되었습니다만 

호모그래피 부분에서 변환행렬이 잘 이해가 안갔습니다 좀더 원리를 알고 싶은데 강의와 책 내용만으로는 부족하더라구요

 

일단 내일은 진도보다는 지난 배운것들을 다시 소화시키도록 하겠습니다

2021/02/26 - [분류 전체보기] - OpenCV_8(특징점 검출&매칭)

 

OpenCV_8(특징점 검출&매칭)

### 해리스,fast,goodFeaturesToTrack import sys import numpy as np import cv2 src = cv2.imread('building.jpg', cv2.IMREAD_GRAYSCALE) if src is None: print('Image load failed!') sys.exit() tm = cv2.Ti..

ghdrldud329.tistory.com

 

728x90

'Data Diary' 카테고리의 다른 글

2021-03-03(OpenCV_10)  (0) 2021.03.03
2021-03-01(OpenCV_9)  (0) 2021.03.01
2021-02-25(OpenCV_7)  (0) 2021.02.25
2021-02-24(OpenCV_6)  (0) 2021.02.24
2021-02-23(OpenCV_5)  (0) 2021.02.23

+ Recent posts