OpenCV图像全景拼接-黑边处理(C++)

参考资料:OpenCV图像全景拼接-黑边处理 - 简书

具体说明参照上述资料。在此基础上做了部分修改或者说优化:

1、直接使用3通道的原图查找边界点,不再转换成灰度图及二值化图像,提高效率。应用范围也是和之前类似,夜景图片效果会不好。这个修改可以提高部分性能。

2、第一次找到对角非全黑点后,会尝试往回找,尽量增大可用面积。

代码如下:


#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

cv::Mat OpenCVTest::quchuHeibian(cv::Mat& img)
{
    qDebug() << "img channels = " << img.channels() << endl;
    int nOffSet = 1;//偏移量,防止弧度极小时,不能往回退
    unsigned long AAtime = 0, BBtime = 0; //check processing time
    AAtime = cv::getTickCount(); //check processing time
    cv::Point2i leftTopPt;
    for (int i = 1; i < img.rows; ++i) {
        Vec3b& bgra = img.at<Vec3b>(i, i);
        if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
            leftTopPt.x = i;
            leftTopPt.y = i;
            int x = leftTopPt.x - 1;
            for (; x > 0; --x) {//从第x列到第0列,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(leftTopPt.y + nOffSet, x);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (leftTopPt.x != x + 1)
            {
                leftTopPt.x = x + 1;
                leftTopPt.y += nOffSet;
            }
            int y = leftTopPt.y - 1;
            for (; y > 0; --y) {//从第y行到第0行,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(y, leftTopPt.x + nOffSet);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (leftTopPt.y != y + 1)
            {
                leftTopPt.y = y + 1;
                leftTopPt.x += nOffSet;
            }
            break;
        }
    }

    cv::Point2i rightTopPt;
    for (int i = 1; i < img.rows; ++i) {
        int x = img.cols - i;
        int y = i;
        Vec3b& bgra = img.at<Vec3b>(y, x);
        if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
            rightTopPt.x = x;
            rightTopPt.y = y;
            x = rightTopPt.x + 1;
            for (; x < img.cols; ++x) {//从第x列到最后一列,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(rightTopPt.y + nOffSet, x);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (rightTopPt.x != x - 1)
            {
                rightTopPt.x = x - 1;
                rightTopPt.y += nOffSet;
            }
            y = rightTopPt.y - 1;
            for (; y > 0; --y) {//从第y行到第0行,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(y, rightTopPt.x - nOffSet);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (rightTopPt.y != y + 1)
            {
                rightTopPt.y = y + 1;
                rightTopPt.x -= nOffSet;
            }
            break;
        }
    }

    cv::Point2i leftBottomPt;
    for (int i = 1; i < img.rows; ++i) {
        int x = i;
        int y = img.rows - i;
        Vec3b& bgra = img.at<Vec3b>(y, x);
        if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
            leftBottomPt.x = x;
            leftBottomPt.y = y;
            x = leftBottomPt.x - 1;
            for (; x > 0; --x) {//从第x列到第0列,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(leftBottomPt.y - nOffSet, x);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (leftBottomPt.x != x + 1)
            {
                leftBottomPt.x = x + 1;
                leftBottomPt.y -= nOffSet;
            }
            y = leftBottomPt.y + 1;
            for (; y < img.rows; ++y) {//从第y行到最后一行,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(y, leftBottomPt.x + nOffSet);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (leftBottomPt.y != y - 1)
            {
                leftBottomPt.y = y - 1;
                leftBottomPt.x += nOffSet;
            }
            break;
        }
    }

    cv::Point2i rightBottomPt;
    for (int i = 1; i < img.rows; ++i) {
        int x = img.cols - i;
        int y = img.rows - i;
        Vec3b& bgra = img.at<Vec3b>(y, x);
        if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
            rightBottomPt.x = x;
            rightBottomPt.y = y;
            x = rightBottomPt.x + 1;
            for (; x < img.cols; ++x) {//从第x列到最后一列,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(rightBottomPt.y - nOffSet, x);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (rightBottomPt.x != x - 1)
            {
                rightBottomPt.x = x - 1;
                rightBottomPt.y -= nOffSet;
            }
            y = rightBottomPt.y + 1;
            for (; y < img.rows; ++y) {//从第y行到最后一行,往回找到最近一个黑点
                Vec3b& bgra = img.at<Vec3b>(y, rightBottomPt.x - nOffSet);
                if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
                    break;
                }
            }
            if (rightBottomPt.y != y - 1)
            {
                rightBottomPt.y = y - 1;
                rightBottomPt.x -= nOffSet;
            }
            break;
        }
    }
    //测试代码1,begin
    //cv::Scalar color2(255, 255, 0);
    // 用黑白图片计算的结果,在原图画个小圆点(黑白图上画不够明显)
    //cv::circle(img, leftTopPt, 5, color2, -1);
    //cv::circle(img, rightTopPt, 5, color2, -1);
    //cv::circle(img, leftBottomPt, 5, color2, -1);
    //cv::circle(img, rightBottomPt, 5, color2, -1);

    //cv::line(img, leftTopPt, rightTopPt, color2);
    //cv::line(img, leftTopPt, leftBottomPt, color2);
    //cv::line(img, rightTopPt, rightBottomPt, color2);
    //cv::line(img, leftBottomPt, rightBottomPt, color2);
    //测试代码1,end

    int topMaxY = max(leftTopPt.y, rightTopPt.y);
    int leftMaxX = max(leftTopPt.x, leftBottomPt.x);
    int rightMinX = min(rightTopPt.x, rightBottomPt.x);
    int bottomMinY = min(leftBottomPt.y, rightBottomPt.y);
    leftTopPt.y = topMaxY;
    rightTopPt.y = topMaxY;
    leftTopPt.x = leftMaxX;
    leftBottomPt.x = leftMaxX;
    rightTopPt.x = rightMinX;
    rightBottomPt.x = rightMinX;
    leftBottomPt.y = bottomMinY;
    rightBottomPt.y = bottomMinY;


    //测试代码2,begin
    //cv::Scalar color(10, 10, 255);
    // 用黑白图片计算的结果,在原图画个小圆点(黑白图上画不够明显)
    //cv::circle(img, leftTopPt, 5, color, -1);
    //cv::circle(img, rightTopPt, 5, color, -1);
    //cv::circle(img, leftBottomPt, 5, color, -1);
    //cv::circle(img, rightBottomPt, 5, color, -1);

    //cv::line(img, leftTopPt, rightTopPt, color);
    //cv::line(img, leftTopPt, leftBottomPt, color);
    //cv::line(img, rightTopPt, rightBottomPt, color);
    //cv::line(img, leftBottomPt, rightBottomPt, color);
    //测试代码2,end

    Mat tempMat = img(cv::Rect(leftTopPt.x, leftTopPt.y, rightBottomPt.x - leftTopPt.x, rightBottomPt.y - leftTopPt.y));

    BBtime = cv::getTickCount(); //check processing time
    float costtime = (BBtime - AAtime) / cv::getTickFrequency();
    QString costimeresult = QString("裁剪时间:%1").arg(costtime);
    qInfo() << costimeresult;
    return tempMat;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值