我尝试使用C++和OpenCV将全景图转换为微小的星球,但图像结果很嘈杂。我不太确定我做错了哪一部分。我认为这与颜色有关。
我尝试使用C++和OpenCV将全景图转换为微小的星球,但图像结果很嘈杂。我不太确定我做错了哪一部分。我认为这与颜色有关。
我提到的教程
http://codeofthedamned.com/index.php/the-little-planet-effect
全景图源
c++ - OpenCV C++中的微小星球全景图-LMLPHP
微小图像结果
c++ - OpenCV C++中的微小星球全景图-LMLPHP

#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
#import "OpenCVWrapper.h"

using namespace cv;

@implementation OpenCVWrapper

+ (UIImage*)createTinyPlanetFromImage: (UIImage*)image {
    Mat pano;
    UIImageToMat(image, pano);

    Mat grayMat;
    RenderProjection(pano, 1000.0, grayMat);

    return MatToUIImage(grayMat);
}

void RenderProjection(Mat &pano, long len, Mat &output) {
    const double k_pi = 3.1415926535897932384626433832795;
    const double k_pi_inverse = 0.31830988618379067153776752674503;

    output.create(len, len, CV_16UC3);
    long half_len = len / 2;
    cv::Size sz = pano.size();

    for (long indexX = 0; indexX < len; ++indexX) {
        for (long indexY = 0; indexY < len; ++indexY) {
            double sphereX = (indexX - half_len) * 10.0 / len;
            double sphereY = (indexY - half_len) * 10.0 / len;
            double Qx, Qy, Qz;

            if (GetIntersection(sphereX, sphereY, Qx, Qy, Qz)) {
                double theta  = std::acos(Qz);
                double phi    = std::atan2(Qy, Qx) + k_pi;
                theta         = theta * k_pi_inverse;
                phi           = phi * (0.5 * k_pi_inverse);
                double Sx     = min(sz.width -2.0, sz.width  * phi);
                double Sy     = min(sz.height-2.0, sz.height * theta);

                output.at<Vec3s>(int(indexY), int(indexX)) = BilinearSample(pano, Sx, Sy);
            }
        }
    }
}

bool GetIntersection(double u, double v, double &x, double &y, double &z) {
  double Nx    = 0.0;
  double Ny    = 0.0;
  double Nz    = 1.0;
  double dir_x = u - Nx;
  double dir_y = v - Ny;
  double dir_z = -1.0 - Nz;

  double a = (dir_x * dir_x) + (dir_y * dir_y) + (dir_z * dir_z);
  double b = (dir_x * Nx) + (dir_y * Ny) + (dir_z * Nz);

  b *= 2;
  double d = b * b;
  double q = -0.5 * (b - std::sqrt(d));

  double t = q / a;

  x = (dir_x * t) + Nx;
  y = (dir_y * t) + Ny;
  z = (dir_z * t) + Nz;

  return true;
}

Vec3s BilinearSample(Mat &image, double x, double y) {
    Vec3s c00 = image.at<Vec3s>(int(y), int(x));
    Vec3s c01 = image.at<Vec3s>(int(y), int(x) + 1);
    Vec3s c10 = image.at<Vec3s>(int(y) + 1, int(x));
    Vec3s c11 = image.at<Vec3s>(int(y) + 1, int(x) + 1);

    double X0 = x - floor(x);
    double X1 = 1.0 - X0;
    double Y0 = y - floor(y);
    double Y1 = 1.0 - Y0;

    double w00 = X0 * Y0;
    double w01 = X1 * Y0;
    double w10 = X0 * Y1;
    double w11 = X1 * Y1;

    short r = short(c00[2] * w00 + c01[2] * w01
                 + c10[2] * w10 + c11[2] * w11);
    short g = short(c00[1] * w00 + c01[1] * w01
                 + c10[1] * w10 + c11[1] * w11);
    short b = short(c00[0] * w00 + c01[0] * w01
                 + c10[0] * w10 + c11[0] * w11);

    return make_BGR(b, g, r);
}

Vec3s make_BGR(short blue, short green, short red) {
  Vec3s result;
  result[0] = blue;
  result[1] = green;
  result[2] = red;

  return result;
}

@end

最佳答案

当我替换UIImageToMat(image,pano);时,问题解决了;和MatToUIImage(grayMat);使用此代码,我们可以删除此 header #import

static void UIImageToMat2(UIImage *image, cv::Mat &mat) {
    assert(image.size.width > 0 && image.size.height > 0);
    assert(image.CGImage != nil || image.CIImage != nil);

    // Create a pixel buffer.
    NSInteger width = image.size.width;
    NSInteger height = image.size.height;
    cv::Mat mat8uc4 = cv::Mat((int)height, (int)width, CV_8UC4);

    // Draw all pixels to the buffer.
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    if (image.CGImage) {
        // Render with using Core Graphics.
        CGContextRef contextRef = CGBitmapContextCreate(mat8uc4.data, mat8uc4.cols, mat8uc4.rows, 8, mat8uc4.step, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
        CGContextDrawImage(contextRef, CGRectMake(0, 0, width, height), image.CGImage);
        CGContextRelease(contextRef);
    } else {
        // Render with using Core Image.
        static CIContext* context = nil; // I do not like this declaration contains 'static'. But it is for performance.
        if (!context) {
            context = [CIContext contextWithOptions:@{ kCIContextUseSoftwareRenderer: @NO }];
        }
        CGRect bounds = CGRectMake(0, 0, width, height);
        [context render:image.CIImage toBitmap:mat8uc4.data rowBytes:mat8uc4.step bounds:bounds format:kCIFormatRGBA8 colorSpace:colorSpace];
    }
    CGColorSpaceRelease(colorSpace);

    // Adjust byte order of pixel.
    cv::Mat mat8uc3 = cv::Mat((int)width, (int)height, CV_8UC3);
    cv::cvtColor(mat8uc4, mat8uc3, cv::COLOR_RGBA2BGR);

    mat = mat8uc3;
}
static UIImage *MatToUIImage2(cv::Mat &mat) {

    // Create a pixel buffer.
    assert(mat.elemSize() == 1 || mat.elemSize() == 3);
    cv::Mat matrgb;
    if (mat.elemSize() == 1) {
        cv::cvtColor(mat, matrgb, cv::COLOR_GRAY2RGB);
    } else if (mat.elemSize() == 3) {
        cv::cvtColor(mat, matrgb, cv::COLOR_BGR2RGB);
    }

    // Change a image format.
    NSData *data = [NSData dataWithBytes:matrgb.data length:(matrgb.elemSize() * matrgb.total())];
    CGColorSpaceRef colorSpace;
    if (matrgb.elemSize() == 1) {
        colorSpace = CGColorSpaceCreateDeviceGray();
    } else {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    CGImageRef imageRef = CGImageCreate(matrgb.cols, matrgb.rows, 8, 8 * matrgb.elemSize(), matrgb.step.p[0], colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault);
    UIImage *image = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);

    return image;
}

关于c++ - OpenCV C++中的微小星球全景图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64371027/

10-09 13:18