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