#05-1. 영상의 밝기 조절

그레이스케일 영상 다루기

  • 동작중 영상을 저장할 새로운 공간 생성 : CV_8UC1 타입 생성

    Mat img2(480, 640, CV_8UC1, Scalar(0));
  • 컬러 영상 변환 cvtColor()

    Mat img1 = imread("jnary.bmp", IMREAD_COLOR);
    Mat img2;
    cvtColor(img1, img2, COLOR_BGR2GRAY);
  • 영상의 밝기 조절

    • 양수값 더하기 : 밝아짐
    • 양수값 빼기 : 어두워짐
    • dst(x, y) = src(x, y) + n
  • 영상의 밝기 조절 함수의 그래프

    • x축 : 입력 영상의 그레이스케일 값
    • y축 : 출력 영상의 그레이스케일 값
    • 255 넘어가는 밝기값은 255로 설정 : overflow 방지 → 포화(saturate)연산
    • dst(x, y) = saturate(src(x, y) + n)

밝기 조절 직접 구현하기

  • add 함수 활용
    dst = cv2.add(src, 100)   # 밝기 증가
    dst = cv2.subtract(src, 100)   # 밝기 감소
  • 결과 영상의 픽셀값 설정 위해 미리 생성
    dst = np.empty(src.shape, src.dtype)
  • 트랙바
    def update(pos):
        dst = cv.add(src, pos)
        cv.imshow('dst', dst)
    cv.createTrackbar('Brightness', 'dst', 50, 100, update)

#05-2. 영상의 명암비 조절

기본적인 명암비 조절

  • 명암비

    • 밝은 영역과 어두운 영역 사이에 드러나는 밝기 차이의 강도
    • contrast
    • 밝은 영역, 어두운 영역 골고루 섞여 있는 영상 → 명암비가 높다
    • 낮은 명암비 → 객체 간 구분 어려움, 흐릿
    • 밝은 건 밝게, 어두운 건 어둡게
  • dst(x, y) = saturate(s * src(x, y))

    s = 0.5

    • 밝은 곳과 어두운 곳의 차이가 128로 줄어듬

    • 낮은 명암비

      s = 2

    • 차이가 510으로 늘어남 (saturate 감안X)

    • 높은 명암비

  • 한계

    • 픽셀값이 포화되어 흰색으로 나타나는 영역 너무 많음
    • 윤곽 구분 어려워짐
    • 일정 상수를 단순히 곱하여 명암비를 조절하는 방식 → 실전에서 사용 X

효과적인 명암비 조절

  1. 밝고 어두운 기준 : 중간값인 128

    • 128보다 크면 더 크게
    • 128보다 작으면 더 작게

    • y = x + (x - 128)*a = (1 + a) x - 128a
    • -1 ≤ a ≤ 0 : 기울기가 0~1사이의 직선 → 명암비 감소
    • a > 0 : 기울이가 1보다 큰 직선 → 명암비 증가

    alpha = 1.0
    dst = cv.convertScaleAbs(src, alpha=1+alpha, beta=-128*alpha)
  2. 밝고 어두운 기준 : 영상의 평균 밝기

    • 평균 밝기보다 밝으면 밝게
    • 평균 밝기보다 어두우면 어둡게

#05-3. 히스토그램 분석

히스토그램 구하기

  • 히스토그램

    • 영상의 픽셀 값 분포를 그래프 형태로 표현한 것
    • 그레이스케일 : 막대 그래프 형태로 표현 (0~255)
    • 컬러 영상 : 3개 색상 성분 조합에 따른 픽셀 개수 계산
  • bin

    • 히스토그램 그래프의 가로축 (bin의 개수 = 8)
    • 그레이스케일 영상의 경우 : 256개의 빈을 가짐
    • 빈 개수를 픽셀 값 범위보다 작게 설정도 가능
    • 빈의 개수 많으면 : 세밀한 형태
    • 빈의 개수 적으면 : 대략적인 형태

OpenCV에서 영상의 히스토그램 구하기

  • calcHist()
    • 여러 장의 영상도 도출 가능 → list 형태로 전달
    • 여러 채널로부터도 가능
    • 빈 개수 조절 가능
    • uniform : 빈의 간격 균등한지 (true)
    • accumulate : 누적 플래스 (false)
    • 반환 : CV_32FC1 타입을 갖는 256*1크기의 행렬
  • calcHist(images, nimages, channels, mask, hist, dims, histSize, ranges, uniform = true, accumulate = false)
    • images : 입력 영상의 배열
    • nimages : 입력 영상 개수
    • channels : 히스토그램을 구할 채널을 나타내는 정수형 배열
    • mask : mask 영상
    • dims : 히스토그램 차원 수
    • histSize : 각 차원의 히스토그램 빈 개수를 나타내는 배열
    • ranges : 각 차원의 히스토그램 범위
    • uniform : 히스토그램 빈 가격이 균등한지 여부 ⭐️
    • accumulate : 누적 플래그 ⭐️
  • python 예시
    channels = [0]
    histSize = [256]
    histRange = [0, 256]
    hist = cv.calcHist([img], channels, None, histSize, histRange)
    • 이미지 한 장이어도 list 형태로 전달
    • multi channel인 경우도 있으니 channel도 list 형태로
  • calcGrayHist()
    • 내부에서 OpenCV 함수 calcHist() 이용
    • 그레이스케일 영상의 히스토그램 표현하는 행렬 hist 반환
    • 결과 hist : 256 * 1 행렬 → 막대그래프 형태로 나타내기 : getGrayHistImage() 높이 100픽셀인 히스토그램 그래프 반환
  • 흰색으로 초기화된 256*100 크기의 영상 imgHist 생성
    def getGrayHistImage(hist):
        _, histMax, _, _ = cv.minMaxLoc(hist)   #최댓값 추출
        imgHist = np.ones((100, 256), np.uint8) * 255   #흰색배경 준비
        for x in range(imgHist.shape[1]):
            pt1 = (x, 100)
            pt2 = (x, 100 - int(hist[x, 0] * 100 / histMax))
            cv.line(imgHist, pt1, pt2, 0)
        return imgHist
    hist_img = getGrayHistImage(hist)
    cv.imshow('histogram', hist_img)
  • 카메라맨 영상의 히스토그램을 화면에 출력
    Mat src = imread("camera.bmp", IMREAD_GRAYSCALE);
    Mat hist = calcGrayHist(src);
    Mat hist_img = getGrayHistImage(hist);
    
    imshow("src", src);
    imshow("srcHist", hist_img);

히스토그램 분석

  • 영상의 밝기와 명암비를 가늠할 수 있는 유용한 도구로 사용

히스토그램 스트레칭

  • 그레이스케일 전 구간에 걸쳐서 나타나도록 변경하는 선형 변환 기법

    → G : 입력 영상 픽셀 값 중 가장 큰/작은 그레이스케일 값

  • 명암비 높아짐

  • 원본 영상의 분포 : Gmin ~ Gmax

    Gmin → 0, Gmax → 255 변환 : 양방향으로 늘리기

  • 변환함수

    • (Gmin, 0), (Gmax, 255) 지나는 직선의 방정식

    • 직선의 기울기 : 255 / (Gmax - Gmin)

    • Y절편 : -255(Gmax - Gmin)

      → OpenCV에서 따로 제공 X

  • minMaxLoc()으로 직접 구현

    gmin, gmax, _, _ = cv.minMaxLoc(src)
    dst = cv.convertScaleAbs(src, alpha=255.0/(gmax-gmin),
                              beta=-gmin/(gmax-gmin)*255)
    cv.imshow('dstHist', getGrayHistImage(calcGrayHist(dst)))
    def histogram_Stretching():
    		src = cv2.imread('jnary.bmp', cv2.IMREAD_GRAYSCALE)
    		gmin, gmax, _, _ = cv2.minMaxLoc(src)
    
    		dst = cv2.convertScaleAbs(src, alpha=255.0/(gmax-gmin), beta=-gmin*255.0/(gmax-gmin))
    		#포화연산까지 진행하는 함수
    
    		cv2.imshow('src', src)
    		cv2.imshow('srcHist', getGrayHistImage(calcGrayHist(src)))
    		
        cv2.imshow('dst', dst)
    		cv2.imshow('dstHist', getGrayHistImage(calcGrayHist(dst)))
    
    		cv2.waitKey()
    		cv2.destroyAllWindows()

히스토그램 평활화

  • Histogram Equalization(균등화, 평탄화)

    • 그레이스케일 전체 영역에서 골고루 나타나도록 변경하는 알고리즘의 하나
    • 특정 그레이스케일 값에서 픽셀 분포가 많이 뭉쳐있는 경우 → 이를 넓게 펼쳐주는 방식
  • 평활화 계산

    • h(g) : 그레이스케일값이 g인 픽셀 개수

    • H(g) : 누적함수(픽셀값 변환 함수)

    • 누적함수의 최댓값이 255가 되도록 정규화

      → 찾고자하는구간까지의픽셀개수/전체픽셀개수 (0~1)

    • Lmax : 영상이 가질 수 있는 최대 밝기 값 (그레이스케일 Lmax = 255)

    • round() : 반올림 함수 → 정수값으로

  • equalizeHist(src, dst)

    • 그레이스케일 영상만 입력으로 받음

    • 3채널로 구성된 컬러영상 입력 시 → ERROR

      def histogram_equalization():
      		src = cv2.imread('jnary.bmp', cv2.IMREAD_GRAYSCALE)
      		...
      		dst = cv2.equalizeHist(src)
      		cv2.imshow('dstHist', getHistImage(calcGrayHist(dst)))

profile
숭실대학교 컴퓨터학부 21

0개의 댓글