在多层彩色胶片尚未问世之前,拍摄彩色照片时所用的照相机..用一只普通照相机,三枚滤色镜(红、绿、蓝),要分别拍三次,得到红分底、绿分底、蓝分底.之后将三种颜色图形叠加还原成彩色照片。
但是由于三次拍摄的角度和位置不是完全一样的,叠加后不能完全对齐,于是结果可能是这样:

image.png

解决办法,以一个通道为基准,另外两个通道进行对齐,之后再合并:

image.png

OpenCV 课程作业:

image.png 读入图像,通道分离

cv::Mat ori_img = cv::imread("../result/reba_un_aligned.jpg");
cv::Mat channels[3];
cv::split(ori_img, channels);

将三个颜色的通道各自组合成三通道BGR 的图像

cv::Mat h10, h20;
cv::Mat blank_ch, bgr_b, bgr_g, bgr_r;
blank_ch =
    cv::Mat::zeros(cv::Size(channels[0].cols, channels[0].rows), CV_8UC1);
cv::Mat channels_b[3]={channels[0], blank_ch, blank_ch};
cv::Mat channels_g[3]={blank_ch, channels[1], blank_ch};
cv::Mat channels_r[3]={blank_ch, blank_ch, channels[2]};
cv::merge(channels_b,3, bgr_b);
cv::merge(channels_g,3, bgr_g);
cv::merge(channels_r,3, bgr_r);

两辆通道之间进行对齐(透视变换)

FindHTotal(bgr_b, bgr_g,&h10);
cv::warpPerspective(channels[1], channels[1], h10,
    cv::Size(blank_ch.cols, blank_ch.rows));


FindHTotal(bgr_b, bgr_r,&h20);
cv::warpPerspective(channels[2], channels[2], h20,
    cv::Size(blank_ch.cols, blank_ch.rows));

查找透视变换矩阵

voidFindHTotal(const cv::Mat src, cv::Mat dst, cv::Mat* h_total){
    printf("FindHTotal E\n");
    cv::Mat gray1;
    cv::Mat gray2;
    cv::cvtColor(src, gray1, cv::COLOR_BGR2GRAY);
    cv::cvtColor(dst, gray2, cv::COLOR_BGR2GRAY);


    // cv::threshold(gray1, gray1, 123, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    // cv::threshold(gray2, gray2, 123, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    // cv::adaptiveThreshold(gray1, gray1, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C,
    //                      cv::THRESH_BINARY, 25, 10);


    // 1.
    // key points
    std::vector<cv::KeyPoint> key_points1;
    std::vector<cv::KeyPoint> key_points2;
    cv::Mat descriptors1, descriptors2;


    // find key points
    cv::Ptr<cv::ORB> orb = cv::ORB::create();
    orb->detectAndCompute(gray1, cv::Mat(), key_points1, descriptors1);
    orb->detectAndCompute(gray2, cv::Mat(), key_points2, descriptors2);


    // 2.
    // match key points
    std::vector<cv::DMatch> matches;
    cv::Ptr<cv::DescriptorMatcher> matcher =
    cv::DescriptorMatcher::create("BruteForce-Hamming");
    matcher->match(descriptors1, descriptors2, matches);
    printf("matches.size() %lu\n", matches.size());
    // sort key points
    // Sort them in the order of their distance
    std::sort(matches.begin(), matches.end());
    // keep good matches
    std::vector<cv::DMatch> good_matches;
    int good_match_num = KEEP_MATCH_PERCENT * matches.size();
    if(good_match_num <5&& matches.size()>=5){
        good_match_num =5;
    }
    printf("good_match_num %d\n", good_match_num);


    good_matches.assign(matches.begin(), matches.begin()+ good_match_num);


    // Draw top matches
    cv::Mat imMatches;
    cv::drawMatches(src, key_points1, dst, key_points2, good_matches, imMatches);
    cv::imwrite("../result/matches.jpg", imMatches);


    // Extract location of good matches
    std::vector<cv::Point2f> points1, points2;
    for(size_t i =0; i < good_matches.size(); i++){
    points1.push_back(key_points1[good_matches[i].queryIdx].pt);
    points2.push_back(key_points2[good_matches[i].trainIdx].pt);
}


    // cv::find h matrix
    *h_total = cv::findHomography(points2, points1, cv::RANSAC);
    printf("FindHTotal X\n");
    // #if IM_SHOW
    //  cv::waitKey(0);
    //  cv::destroyAllWindows();
    // #endif
}

合并对齐后的通道

  cv::Mat new_channels[3]={channels[0], channels[1], channels[2]};
  cv::Mat merged_img;
  cv::merge(new_channels,3, merged_img);

image.png

[[2022-02-18-png 透明 alpha 通道]]