Newer
Older
LumenProfiler / lumen_profiler.py
import csv

import cv2
import numpy as np

area_ratio = 80
enable_display = True


def on_slider(pos):
    global area_ratio
    area_ratio = pos


win_org = "original image"
win_value = "value image"

cap = cv2.VideoCapture("サンプル動画_気管支鏡.mp4")

if enable_display:
    cv2.namedWindow(win_org, cv2.WINDOW_AUTOSIZE)
    cv2.namedWindow(win_value, cv2.WINDOW_AUTOSIZE)
    cv2.createTrackbar("area", win_org, area_ratio, 300, on_slider)

frame_count = 0
csv_data = []
while True:
    # 画像読み込み
    ret, frame = cap.read()
    if not ret:
        # break
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
        frame_count = 0
        print("rewind")
        continue
    # 輝度画像生成
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    val_img = hsv[:, :, 2]
    # 累積ヒストグラム算出
    hist = cv2.calcHist([val_img], [0], None, [256], [0, 256])
    # acc_hist = np.zeros(256, np.float32)
    # acc_hist[0] = hist[0]
    # しきい値決定
    thres = -1
    sum = 0
    for i in range(0, 256):
        sum += hist[i]
        # acc_hist[i] = acc_hist[i - 1] + hist[i]
        if thres < 0 and sum > (val_img.size * area_ratio / 1000):
            thres = i
            break
    # 気道のマスク生成
    val_img = cv2.GaussianBlur(val_img, (13, 13), 5.0)
    mask = cv2.threshold(val_img, thres, 255, cv2.THRESH_BINARY_INV)[1]
    # mask = cv2.threshold(val_img, area_ratio, 255, cv2.THRESH_BINARY_INV)[1]
    # kernel = np.ones((5, 5), np.uint8)
    # mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

    retval, labels, stats, centroids = cv2.connectedComponentsWithStats(mask)
    target_label = -1
    min_dist = 0
    center = [frame.shape[1] / 2, frame.shape[0] / 2]
    # print([stats[i, cv2.CC_STAT_AREA] for i in range(retval)])
    if retval > 1:
        for i in range(1, retval):
            dist = np.linalg.norm(centroids[i] - center, 2)
            if stats[i, cv2.CC_STAT_AREA] > 200 and (
                dist < min_dist or target_label < 0
            ):
                min_dist = dist
                target_label = i

    selected_mask = np.zeros(mask.shape, np.uint8)
    selected_mask[labels == target_label] = 255

    contours, hierarchy = cv2.findContours(
        selected_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )

    etime = frame_count * 1.0 / 30.0
    cv2.putText(
        frame,
        "frame%4d  time %.3fs" % (frame_count, etime),
        (10, 25),
        cv2.FONT_HERSHEY_TRIPLEX,
        0.7,
        (255, 0, 0),
        1,
    )
    cv2.putText(
        frame,
        "area ratio=%.1f %%" % (area_ratio / 10),
        (10, 50),
        cv2.FONT_HERSHEY_TRIPLEX,
        0.7,
        (255, 0, 0),
        1,
    )

    if len(contours) > 0:
        # for i in range(len(contours)):
        cv2.drawContours(frame, contours, 0, (0, 255, 255), 3)

        area = cv2.contourArea(contours[0])
        perimeter = cv2.arcLength(contours[0], True)
        if perimeter > 0:
            circle_level = 4.0 * np.pi * area / (perimeter * perimeter)
        else:
            circle_level = 0
        # print(circle_level)
        cv2.putText(
            frame,
            "circle level=%.1f %%" % (circle_level * 100),
            (10, 75),
            cv2.FONT_HERSHEY_TRIPLEX,
            0.7,
            (255, 0, 0),
            1,
        )
        cv2.putText(
            hsv,
            "threshold=%d" % (thres),
            (10, 30),
            cv2.FONT_HERSHEY_TRIPLEX,
            0.7,
            (0, 0, 0),
            1,
        )

    # frame[labels == target_label] = [0, 0, 0]

    # cv2.imwrite("output/cl_%04d.jpg" % frame_count, frame)

    csv_data.append([frame_count, etime, area_ratio / 10, thres, circle_level * 100])

    if enable_display:
        cv2.imshow(win_org, frame)
        cv2.imshow(win_value, hsv[:, :, 2])

        if cv2.waitKey(30) & 0xFF == 27:
            break
    frame_count += 1

# with open("output/analysis.csv", "w", newline="") as f:
#     writer = csv.writer(f)
#     writer.writerow(
#         ["frame", "time(s)", "area ratio(%)", "threshold", "circle level(%)"]
#     )
#     writer.writerows(csv_data)

cap.release()
cv2.destroyAllWindows()