[opencv] Image Overlay

spring·2021년 7월 20일
0
def image_overlay(bgimg3c, fgimg4c):
    b, g, r, a = cv2.split(fgimg4c)
    mask = cv2.merge([a, a, a])
    fgimg3c = cv2.merge([b, g, r])
    mask = mask / 255.0
    mask_inv = 1.0 - mask
    ret = (bgimg3c * mask_inv + fgimg3c * mask).clip(0, 255)
    return ret.astype(np.uint8)

컴퓨터비전 딥러닝을 하다 보면 가상 데이터(Synthetic Data)를 생성해야 하는 경우가 종종 있다.

3채널(RGB) 이미지와 4채널(RGBA) 이미지를 오버레이 하는 방법인데 데이터 증강의 한 기법으로 사용할 수 있다.

배경에 원하는 객체를 붙일 수도 있고 False Positive로 검출되는 객체를 인위적으로 Background에 넣어 FP를 낮출 수도 있다.

3D 모델이 있다면 더할 나위 없이 좋겠지만 Segmentation 데이터를 구하는 것도 어려운 마당에 3D 모델 구하는 게 쉽지 않다.

아래 코드는 Image Overlay에 대한 C++/Python 코드이다.

참조한 코드는 C++ OverlayImage 인데 성능 문제로 코드를 수정하였다.

cv::Mat OverlayImage(const cv::Mat& bg3c, const cv::Mat& fg4c, cv::Point2i location = cv::Point2i(0, 0)) {
    if (bg3c.channels() != 3 || fg4c.channels() != 4)
        CV_Error(cv::Error::BadNumChannels, "Invalid input image channel");
    cv::Mat ret = bg3c.clone();
    int y = std::max(location.y, 0);
    int h = std::min(bg3c.rows, fg4c.rows + location.y);
    int x = std::max(location.x, 0);
    int w = std::min(bg3c.cols, fg4c.cols + location.x);
    std::vector<cv::Mat> fg_rgba;
    cv::split(fg4c, fg_rgba);
    cv::Mat alpha = fg_rgba[3];
    fg_rgba.pop_back();
    cv::Mat fg;
    cv::merge(fg_rgba, fg); //3 channel foreground
    
    cv::Mat r_opacity = (1 - alpha(cv::Rect(x - location.x, y - location.y, w, h)) / 255.);
    std::vector<cv::Mat> r_opacity_v = { r_opacity,r_opacity,r_opacity };
    cv::merge(r_opacity_v, r_opacity);
    cv::Mat opacity = alpha(cv::Rect(x - location.x, y - location.y, w, h))/255.;
    std::vector<cv::Mat> opacity_v = { opacity,opacity,opacity };
    cv::merge(opacity_v, opacity);

    cv::Mat newbg, newfg;
    cv::multiply(bg3c(cv::Rect(x, y, w, h)), (r_opacity), newbg);
    cv::multiply(fg(cv::Rect(x - location.x, y - location.y, w, h)), (opacity), newfg);
    cv::add(newbg,newfg, ret(cv::Rect(x, y, w, h)));
    return ret;
}

마찬가지로 Python 코드도 아래와 같다.
참조한 python OverlayImage

def OverlayImage(bg3c: np.ndarray, fg4c: np.ndarray, loc: typing.Tuple):
    if bg3c.shape[2] != 3 or fg4c.shape[2] != 4:
        raise Exception("Invalid input channel")
    ret = bg3c.copy()
    y = max(loc[1], 0)
    h = min(bg3c.shape[0], fg4c.shape[0] + loc[1])
    x = max(loc[0], 0)
    w = min(bg3c.shape[1], fg4c.shape[1] + loc[0])
    fg_bgra = cv2.split(fg4c)
    alpha = fg_bgra[3]
    fg = cv2.merge([*fg_bgra][:-1])
    r_opacity = 1 - alpha[y:y + h, x:x + w] / 255.
    opacity = alpha[y:y + h, x:x + w] / 255.
    newbg = cv2.multiply(bg3c[y:y + h, x:x + w].astype(np.float), cv2.merge([r_opacity, r_opacity, r_opacity]))
    fx = x - loc[0]
    fy = y - loc[1]
    newfg = cv2.multiply(fg[fy:fy + h, fx:fx + w].astype(np.float), cv2.merge([opacity, opacity, opacity]))
    ret[y:y + h, x:x + w] = cv2.add(newbg, newfg)
    return ret
profile
Researcher & Developer @ NAVER Corp | Designer @ HONGIK Univ.

0개의 댓글