How to convert image to cylindrical shape? - c++

I am using objective c language.
I want to convert my image to cylindrical shape. Here I am using below cpp file code to convert image.
cv::Mat CylindricalWarper2 (Mat img)
{
cv::Mat destImgMat(img.size(), CV_8U);
for(int y = 0; y < img.rows; y++)
{
for(int x = 0; x < img.cols; x++)
{
cv::Point2f current_pos(x,y);
current_pos = convert_pt1dd(current_pos, img.cols, img.rows);
cv::Point2i top_left((int)current_pos.x,(int)current_pos.y);
if(top_left.x < 0 || top_left.x > img.cols-2 || top_left.y < 0 ||
top_left.y > img.rows-2)
{
continue;
}
//bilinear interpolation
float dx = current_pos.x-top_left.x;
float dy = current_pos.y-top_left.y;
float weight_tl = (1.0 - dx) * (1.0 - dy);
float weight_tr = (dx) * (1.0 - dy);
float weight_bl = (1.0 - dx) * (dy);
float weight_br = (dx) * (dy);
uchar value = weight_tl * img.at<uchar>(top_left) +
weight_tr * img.at<uchar>(top_left.y,top_left.x+1) +
weight_bl * img.at<uchar>(top_left.y+1,top_left.x) +
weight_br * img.at<uchar>(top_left.y+1,top_left.x+1);
destImgMat.at<uchar>(y,x) = value;
}
}
return destImgMat;
}
cv::Point2f convert_pt1dd(cv::Point2f point,int w,int h)
{
cv::Point2f pc(point.x-w/2,point.y-h/2);
float f = w;
float r = w;
float omega = w/2;
float z0 = f - sqrt(r*r-omega*omega);
float zc = (2*z0+sqrt(4*z0*z0-4*(pc.x*pc.x/(f*f)+1)*(z0*z0-r*r)))/(2*
(pc.x*pc.x/(f*f)+1));
cv::Point2f final_point(pc.x*zc/f,pc.y*zc/f);
final_point.x += w/2;
final_point.y += h/2;
return final_point;
}
With this code I got the cylindrical shape but my image cut down. Not get the full cylindrical projection image,My image look like below,
Image link
I want to display my full image in cylindrical shape.
If some source or help provided, greatly Appreciated.
Thanks in advance

Related

Rotate RGBA image clockwise

I have 1d array (size = 4 * width * height + 1) of pixels of RGBA png image. I want to rotate image by X degrees clockwise. I already know how to do it for 90 degrees, but I guess I have some problem with trigonometry.
Here's the code:
std::pair<int, int> move(int x, int y, double rad) {
return {x * cos(rad) - y * sin(rad), x * cos(rad) + y * sin(rad)};
}
void turn(int deg) {
if (deg < 0) {
deg = 360 + deg;
}
double rad = deg * (M_PI / (double)180);
unsigned int oldWidth = width;
width = lround(sqrt(height * height + width * width));
height = lround(sqrt(height * height + oldWidth * oldWidth));
std::vector<unsigned char> output(rawPixels.size());
for (int X = 0; X < width; ++X) {
for (int Y = 0; Y < height; ++Y) {
for (int chan = 0; chan < CHANNELS_COUNT; ++chan) {
std::pair<int, int> xy = move(X, Y, rad);
output[(X * height + Y) * CHANNELS_COUNT + chan] = rawPixels[
((height - 1 - xy.second) * width + xy.first) * CHANNELS_COUNT + chan];
}
}
}
rawPixels = output;
}
It's ok to use addition arrays, but I don't want to use OpenCV or any other libraries.

pcl::Pointcloud to cv::Mat depth image

I am converting this depth image to a pcl::pointcloud.
using the following:
PointCloud::Ptr PointcloudUtils::RGBDtoPCL(cv::Mat depth_image, Eigen::Matrix3f& _intrinsics)
{
PointCloud::Ptr pointcloud(new PointCloud);
float fx = _intrinsics(0, 0);
float fy = _intrinsics(1, 1);
float cx = _intrinsics(0, 2);
float cy = _intrinsics(1, 2);
float factor = 1;
depth_image.convertTo(depth_image, CV_32F); // convert the image data to float type
if (!depth_image.data) {
std::cerr << "No depth data!!!" << std::endl;
exit(EXIT_FAILURE);
}
pointcloud->width = depth_image.cols; //Dimensions must be initialized to use 2-D indexing
pointcloud->height = depth_image.rows;
pointcloud->resize(pointcloud->width*pointcloud->height);
#pragma omp parallel for
for (int v = 0; v < depth_image.rows; v += 4)
{
for (int u = 0; u < depth_image.cols; u += 4)
{
float Z = depth_image.at<float>(v, u) / factor;
PointT p;
p.z = Z;
p.x = (u - cx) * Z / fx;
p.y = (v - cy) * Z / fy;
p.z = p.z / 1000;
p.x = p.x / 1000;
p.y = p.y / 1000;
pointcloud->points.push_back(p);
}
}
return pointcloud;
}
this works great, I have run some processing on the cloud, and now I need to convert the pointcloud back to a cv::Mat depth image. I cannot find an example for this, and am having trouble getting m head around it. What is the opposite of the above function?
How can i convert a pcl::pointcloud back to a cv::mat?
Thank you.
This is untested code, since I don't have point cloud on my machine.
From your own conversion code I am assuming your image a single channel image.
void PCL2Mat(PointCloud::Ptr pointcloud, cv::Mat& depth_image, int original_width, int original_height)
{
if (!depth_image.empty())
depth_image.release();
depth_image.create(original_height, original_width, CV_32F);
int count = 0;
#pragma omp parallel for
for (int v = 0; v < depth_image.rows; ++v)
{
for (int u = 0; u < depth_image.cols; ++u)
{
depth_image.at<float>(v, u) = pointcloud->points.at(count++).z * 1000;
}
}
depth_image.convertTo(depth_image,CV_8U);
}
I don't know about OpenCV methods, but in case you do something that makes your point cloud unstructured your process could be something like this
% rescale the points by 1000
p.x = p.x * 1000; p.y = p.y * 1000; p.z = p.z * 1000;
% project points on image plane and correct center point + factor
image_p.x = ( p.x * fx / p.z -cf ) * factor;
image_p.y = ( p.y * fy / p.z -cy ) * factor;
Now depending on what you have done with the point cloud the points might not map exactly to image matrix pixel center points (or top left corner for some applications) or you might be missing points -> NaN/0 value pixels. How you process that is up to you, but the most simple way would be to cast image_p.x and image_p.y as integers, make sure they are withing image boundaries and set
depth_image.at<float>(image_p.y, image_p.x) = p.Z;`

Can I replace this interpolate function with the one offered by opencv?

I'm have this function taken from here:
bool interpolate(const Mat &im, float ofsx, float ofsy, float a11, float a12, float a21, float a22, Mat &res)
{
bool ret = false;
// input size (-1 for the safe bilinear interpolation)
const int width = im.cols-1;
const int height = im.rows-1;
// output size
const int halfWidth = res.cols >> 1;
const int halfHeight = res.rows >> 1;
int dim = res.rows * res.cols;
float *out = res.ptr<float>(0);
for (int j=-halfHeight; j<=halfHeight; ++j)
{
const float rx = ofsx + j * a12;
const float ry = ofsy + j * a22;
#pragma omp simd
for(int i=-halfWidth; i<=halfWidth; ++i)
{
float wx = rx + i * a11;
float wy = ry + i * a21;
const int x = (int) floor(wx);
const int y = (int) floor(wy);
if (x >= 0 && y >= 0 && x < width && y < height)
{
// compute weights
wx -= x; wy -= y;
// bilinear interpolation
*out++ =
(1.0f - wy) * ((1.0f - wx) * im.at<float>(y,x) + wx * im.at<float>(y,x+1)) +
( wy) * ((1.0f - wx) * im.at<float>(y+1,x) + wx * im.at<float>(y+1,x+1));
} else {
*out++ = 0;
ret = true; // touching boundary of the input
}
}
}
return ret;
}
I don't know what interpolation is in details, but looking at this opencv page, it seems that it's a bilinear interpolation using INTER_LINEAR. The point is that I don't know how to call an equivalent opencv function for the code above.
This function is called in two different points here.
You can't solely apply simple an interpolation using openCV,
it has to be part of image processing operation, e.g warp or resize operation.
I think you are trying to vectorize a warp affine, the easiest way and most efficient code on Intel platform would be to use IPP.
Otherwise, I'd let Opencv Warp affine do the job.

Setting transparency in OpenCV not working

I am setting transparency for a four channeled Mat like this (Based on some calculations). But when I am showing the image the on window there is no change happening for the Image. Any help would be a great support.
void feather_touch(Rect enclosingRect, Mat frame){
Point center(frame.size().width * 0.5, frame.size().height * 0.5);
int inclussive_circle_radius = (sqrt((frame.cols * frame.cols + frame.rows * frame.rows))) / 2;
for(int i = 0; i < frame.rows; i++){
for(int j = 0; j < frame.cols; j++){
Point point(i, j);
if(!inRect(point, enclosingRect)){
Vec4b channels = frame.at<Vec4b>(i, j);
int dx = center.x - point.x;
int dy = center.y - point.y;
int dist = sqrt((dx * dx) + (dy * dy));
float alpha = (float)dist/(float)inclussive_circle_radius;
int a = (int)((1 - alpha) * 255);
frame.at<Vec4b>(i, j)[3] = a;
}
}
}
}
bool inRect(cv::Point p,Rect rect) {
return p.x >= rect.x && p.x <= (rect.x + rect.width) && p.y >= rect.y && p.y <= (rect.y + rect.height);
}
I got the answer though: imshow in OpenCV doesn't support transparency.I replaced it by using addWeighted functionality. Now my function look like this:
float alpha = ((float)dist/(float)inclussive_circle_radius);
//int a = (int)((1 - alpha) * 255);
//frame.at<Vec4b>(i, j)[3] = a;
Rect rect(j, i, 1, 1);
Mat mat = frame(rect);
Mat sub = layer(rect);
if(dist > (enclosingRect.width*0.5)){
addWeighted(mat, alpha, sub, 1 - alpha, 0, mat);
mat.copyTo(frame(rect));
}else{
sub.copyTo(frame(rect));
}

Rotating image not working

I'm trying to rotate an image using openFrameworks, but I have a problem. My rotated image is red instead of its original color.
void testApp::setup(){
image.loadImage("abe2.jpg");
rotatedImage.allocate(image.width, image.height, OF_IMAGE_COLOR);
imageCenterX = image.getWidth() / 2;
imageCenterY = image.getHeight() / 2;
w = image.getWidth();
h = image.getHeight();
int degrees = 180;
float radians = (degrees*(PI / 180));
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int index = image.getPixelsRef().getPixelIndex(x, y);
int newX = (cos(radians) * (x - imageCenterX) - sin(radians) * (y - imageCenterY) + imageCenterX);
int newY = (sin(radians) * (x - imageCenterX) + cos(radians) * (y - imageCenterY) + imageCenterY);
int newIndex = rotatedImage.getPixelsRef().getPixelIndex(newX, newY);
rotatedImage.getPixelsRef()[newIndex] = image.getPixelsRef()[index];
}
}
rotatedImage.update();
}
void testApp::update(){
}
void testApp::draw(){
image.draw(0,0);
rotatedImage.draw(0,400);
}
Can someone tell me what I am doing wrong?
If your image has three color components (Red, Green, Blue), you need to transform all three of those. The following should do the trick:
rotatedImage.getPixelsRef()[newIndex] = image.getPixelsRef()[index];
rotatedImage.getPixelsRef()[newIndex+1] = image.getPixelsRef()[index+1];
rotatedImage.getPixelsRef()[newIndex+2] = image.getPixelsRef()[index+2];