OpenCV's projectPoints function - c++

I'm currently trying to implement a example of OpenCV's projectPoints method. The idea behind this method is taking as input a set of 3D points, translation/rotation vector's of a given camera and its distortion coeficients, output the corresponding 2D points in the image plane.
The source of code is as follows:
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <string>
std::vector<cv::Point3d> Generate3DPoints();
int main(int argc, char* argv[])
{
// Read 3D points
std::vector<cv::Point3d> objectPoints = Generate3DPoints();
std::vector<cv::Point2d> imagePoints;
cv::Mat intrisicMat(3, 3, cv::DataType<double>::type); // Intrisic matrix
intrisicMat.at<double>(0, 0) = 1.6415318549788924e+003;
intrisicMat.at<double>(1, 0) = 0;
intrisicMat.at<double>(2, 0) = 0;
intrisicMat.at<double>(0, 1) = 0;
intrisicMat.at<double>(1, 1) = 1.7067753507885654e+003;
intrisicMat.at<double>(2, 1) = 0;
intrisicMat.at<double>(0, 2) = 5.3262822453148601e+002;
intrisicMat.at<double>(1, 2) = 3.8095355839052968e+002;
intrisicMat.at<double>(2, 2) = 1;
cv::Mat rVec(3, 1, cv::DataType<double>::type); // Rotation vector
rVec.at<double>(0) = -3.9277902400761393e-002;
rVec.at<double>(1) = 3.7803824407602084e-002;
rVec.at<double>(2) = 2.6445674487856268e-002;
cv::Mat tVec(3, 1, cv::DataType<double>::type); // Translation vector
tVec.at<double>(0) = 2.1158489381208221e+000;
tVec.at<double>(1) = -7.6847683212704716e+000;
tVec.at<double>(2) = 2.6169795190294256e+001;
cv::Mat distCoeffs(5, 1, cv::DataType<double>::type); // Distortion vector
distCoeffs.at<double>(0) = -7.9134632415085826e-001;
distCoeffs.at<double>(1) = 1.5623584435644169e+000;
distCoeffs.at<double>(2) = -3.3916502741726508e-002;
distCoeffs.at<double>(3) = -1.3921577146136694e-002;
distCoeffs.at<double>(4) = 1.1430734623697941e+002;
std::cout << "Intrisic matrix: " << intrisicMat << std::endl << std::endl;
std::cout << "Rotation vector: " << rVec << std::endl << std::endl;
std::cout << "Translation vector: " << tVec << std::endl << std::endl;
std::cout << "Distortion coef: " << distCoeffs << std::endl << std::endl;
std::vector<cv::Point2f> projectedPoints;
cv::projectPoints(objectPoints, rVec, tVec, intrisicMat, distCoeffs, projectedPoints);
/*for (unsigned int i = 0; i < projectedPoints.size(); ++i)
{
std::cout << "Image point: " << imagePoints[i] << " Projected to " << projectedPoints[i] << std::endl;
}*/
std::cout << "Press any key to exit.";
std::cin.ignore();
std::cin.get();
return 0;
}
std::vector<cv::Point3d> Generate3DPoints()
{
std::vector<cv::Point3d> points;
double x, y, z;
x = .5; y = .5; z = -.5;
points.push_back(cv::Point3d(x, y, z));
x = .5; y = .5; z = .5;
points.push_back(cv::Point3d(x, y, z));
x = -.5; y = .5; z = .5;
points.push_back(cv::Point3d(x, y, z));
x = -.5; y = .5; z = -.5;
points.push_back(cv::Point3d(x, y, z));
x = .5; y = -.5; z = -.5;
points.push_back(cv::Point3d(x, y, z));
x = -.5; y = -.5; z = -.5;
points.push_back(cv::Point3d(x, y, z));
x = -.5; y = -.5; z = .5;
points.push_back(cv::Point3d(x, y, z));
for(unsigned int i = 0; i < points.size(); ++i)
{
std::cout << points[i] << std::endl << std::endl;
}
return points;
}
The application crashes when I try to run the projectPoints method and I have no idea why. Any help would be greatly appreciated.

It seems to be complaining about the type of the output vector of points. Try to replace your call to projectPoints:
cv::projectPoints(objectPoints, rVec, tVec, intrisicMat, distCoeffs, projectedPoints);
by this call:
cv::projectPoints(objectPoints, rVec, tVec, intrisicMat, distCoeffs, imagePoints);
This uses the variable of type std::vector<cv::Point2d> instead of std::vector<cv::Point2f>.

Related

How can I get the pixels values and coordinates inside bounding box (rect) in c++? is there any method?

I'm trying to get the pixel's values and their x and y coordinate inside the bounding box of objects.
here's my part of the code :
vector<Detector::Object> detected_objects;
for (int i = 0; i < detected_objects.size(); ++i) {
int xmin = detected_objects[i].rect.x;
int ymin = detected_objects[i].rect.y;
int width = detected_objects[i].rect.width;
int height = detected_objects[i].rect.height;
Rect rect(xmin, ymin, width, height); //The upper left coordinates (x, y) and the length (x) and width (y) of the rectangle
cv::rectangle(osrc, rect, Scalar(200, 200, 10), 1, LINE_8, 0); // set rectangle color
// std::cout << "\n coord: \n" << rect;
//std::cout << "# of contour points: " << rect.size() << std::endl;
int xmax = xmin + width;
int ymax = ymin + height;
for (size_t x = xmin; x < xmax; x++)
{
for (size_t y = ymin; y < ymax; y++)
{
}
}
}
Any help is appreciated!
v::Mat BoxValues = cv::Mat::zeros(detected_objects[i].rect.Height, detected_objects[i].rect.Width,type());
BoxValues = osrc(cv::Range(int(detected_objects[i].rect.y()),int(detected_objects[i].rect.y())+detected_objects[i].rect.Height),cv::Range(int(detected_objects[i].rect.x()),int(detected_objects[i].rect.x())+detected_objects[i].rect.Wigth));
Result BoxValues will holds the Inside the Bounding box Pixcel Values.
Regarding the coordinate hope we can get by the cv::Range.
I found a solution!
Here's the part of the code to extract the pixels values and coordinates inside of yolo bounding boxes :
for (i = 0; i < detected_objects.size(); ++i) {
xmin = detected_objects[i].rect.x;
ymin = detected_objects[i].rect.y;
width = detected_objects[i].rect.width;
height = detected_objects[i].rect.height;
xmax = xmin + width;
ymax = ymin + height;
Rect rect(xmin, ymin, width, height); //The upper left coordinates (x, y) and the length (x) and width (y) of the rectangle
cv::rectangle(osrc, rect, Scalar(200, 200, 10), 1, LINE_8, 0); // set rectangle color
std::cout << "rect number:" << rect << "[" << i << "]" << "\n"; // print the number of detected objects
for (x = xmin; x < xmax; x++)
{
for (y = ymin; y < ymax; y++)
{
// pixel_values = osrc.at<Vec3b>(x, y); // for 3 channels output
// Scalar intensity = osrc.at<uchar>(y, x);
Scalar intensity = osrc.at<uchar>(Point(x, y)); //get pixel intensity from one channel (Grayscale image)
std::cout << "Pixel intensity: " << intensity << "[" << i << "]" << "\n";
//allocate the array
int** arr = new int* [xmax];
for (int k = 0; k < xmax; k++)
arr[k] = new int[ymax];
// use the array
cout << "coords: "<<"[" << x << "," << y << "]: \n ";
//cout << arr[x][y] << endl;
//deallocate the array
for (int k = 0; k < xmax; k++)
delete[] arr[k];
delete[] arr;
// std::cout << " \npixel: \n " << Point(x,y);
// pixelValue = GetPixel(hDC, pos.x, pos.y);
// std::cout << " \pixelValue: \n" << pixelValue;
}
}
}

How to fix vertical artifact lines in a vertex array in SFML, WITH pixel perfect zoom/move?

I have been working on a 2D top-down game solely in SFML and C++, that has a tilemap. I cannot rid the tilemap of vertical line artifacts when zooming in and out or moving the render view at different zoom levels. I attached an image below of the problem; circled in red.
[edit]
There are a lot of factors that make this bug inconsistent.
If I use a tile_atlas from only one tile, there is no artifacts. If I map each texture to a tile a.k.a not using vertex arrays; I did not see any artifacts but it is anywhere from 10x to 15x slower with the same number of tiles on the screen. I have tried finding zoom levels that don't cause artifacts, and there are some. but the levels are almost random and makes zoom in and out, not smooth and choppy.
I have tried numerous tutorials and forum "fixes" that have not completely worked. I have completely rewrote the underlying tile engine 4 separate times to no avail.
https://en.sfml-dev.org/forums/index.php?topic=15747.0
topic=14504
topic=5952
topic=13637.15
https://www.sfml-dev.org/tutorials/2.5/graphics-view.php
https://www.binpress.com/creating-city-building-game-with-sfml/
https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php
[edit]
I have read the Terreria scaling issue, the fix to make extra large textures then scale, or multiple textures, one for each zoom level. seem exhaustive. I am looking for a programmatic way of achieving the scaling correctly.
This is post is my last attempt to fix the code, otherwise I will need to change languages.
I believe the main issue comes from the zoom in/out functions of the program.
I have tried many, variations/attempt to get this to work +0.5f offset,+0.375f offset, not pixel perfect
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;
float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
Here is the entire code.
main.cpp
#include "chunk_map.h"
#include "tile_atlas.h"
#include <vector>
//#include "main.h"
#include "map.h"
#include <iostream>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/View.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>
#include "animation_handler.h"
int main(int argc, char* argv[])
{
sf::RenderWindow app(sf::VideoMode(600, 600), "Tilemap Example");
// Hard set fps to monitor refresh rate.
// textures to load.
/*text_mgr.loadTexture("grass", "grass.png");
text_mgr.loadTexture("high_grass", "high_grass.png");
Animation staticAnim(0, 0, 1.0f);
tileAtlas["grass"] = Tile(32, 1, text_mgr.getRef("grass"),{ staticAnim },
TileType::GRASS, 50, 0, 1);
tileAtlas["high_grass"] = Tile(32, 1, text_mgr.getRef("high_grass"),{ staticAnim },
TileType::HIGH_GRASS, 100, 0, 1);*/
//Map map;
//map.load(50, 50, tileAtlas);
#ifdef NDEBUG
app.setVerticalSyncEnabled(true);
std::cout << "#################\n";
#endif // DEBUG
//app.setVerticalSyncEnabled(true);
sf::View cam = app.getDefaultView();
tile_atlas atlas = tile_atlas();
std::vector<chunk_map> map;
for (int x = 0; x < 5; x++)
{
for (int y = 0; y < 5; y++)
{
map.push_back(chunk_map());
map.back().set_texture(atlas.get_atlas());
map.back().set_position(10 * x, 10 * y, 10 * (x + 1), 10 * (y + 1));
map.back().load_tiles();
}
}
sf::Clock clock;
int checked = 0;
int last_sq = 600;
while (app.isOpen())
{
//sf::Time elapsed = clock.restart();
//float dt = elapsed.asSeconds();
sf::Event eve;
while (app.pollEvent(eve))
if (eve.type == sf::Event::Closed)
app.close();
if (sf::Keyboard::isKeyPressed(sf::Keyboard::P))
std::cout << "view x: " << cam.getSize().x << "\tview y: " << cam.getSize().y << std::endl;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
{
float zoom_out = 1.005f;
float nz = last_sq * zoom_out;
nz = std::ceil(nz);
float now = nz / last_sq;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;
float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
cam.move(-0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
cam.move(0.f, 0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
cam.move(0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
sf::Time elapsed = clock.getElapsedTime();
float t = elapsed.asSeconds();
int time = std::floor(t);
if (checked < time)
{
checked = time;
cam.move(0.01f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
app.close();
app.setView(cam);
#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);
for (int i = 0; i < 25; i++)
{
app.draw(map.at(i));
}
app.display();
}
}
chunk_map.h
#pragma once
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <vector>
class chunk_map : public sf::Drawable
{
private:
//change values of these to match your needs and improve performance
enum { tilesize = 32, chunksize = 32};
//tile size float
float tile_size_float = 32.0f;
// Draw chunk
virtual void draw(sf::RenderTarget& target, sf::RenderStates states)const;
// texture for chunk
sf::Texture m_texture;
// chunk dimensions
int tiles_per_chunk_x;
int tiles_per_chunk_y;
//start x and y and ending x and y scaled to tile size. a.k.a.
// 1,1 = tile 1,1. 10,10, equals tile 10,10
int chunk_start_x;
int chunk_start_y;
int chunk_end_x;
int chunk_end_y;
// Vertex array of positions of tiles in chunk
std::vector<std::vector<sf::VertexArray> > m_chunks;
// Append tiles.
void append_tile(int gx, int gy, sf::VertexArray& garr);
public:
chunk_map();
~chunk_map();
void load_tiles();
void set_texture(sf::Texture);
void set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y);
};
chunk_map.cpp
#include "chunk_map.h"
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Vertex.hpp>
chunk_map::chunk_map()
{
}
chunk_map::~chunk_map()
{
}
void chunk_map::load_tiles()
{
/*
Tile loading this is were the tiles are added to the Quadrantics of the tilemap.
this is the entire chunk_map loop
*/
if ((chunk_end_x * chunk_end_y) == 0)//empty map - possibly forgotten to fill data struct
{
//to stop displaying at all after failed loading:
tiles_per_chunk_x = 0;
tiles_per_chunk_y = 0;
m_chunks.clear();
return;
}
chunk_map::tiles_per_chunk_x = (chunk_end_x / chunksize) + 1;
chunk_map::tiles_per_chunk_y = (chunk_end_y / chunksize) + 1;
m_chunks.assign(tiles_per_chunk_x, std::vector<sf::VertexArray>(tiles_per_chunk_y, sf::VertexArray(sf::Quads)));//ready up empty 2d arrays
for (int iy = chunk_start_y; iy < chunk_end_y; ++iy)
{
for (int ix = chunk_start_x; ix < chunk_end_x; ++ix)
{
append_tile(ix, iy, m_chunks[ix / chunksize][iy / chunksize]);
}
}
}
void chunk_map::append_tile(int gx, int gy, sf::VertexArray& garr)
{
/*
This is the specific tile vertex, broken from the other function to decrease complexitity.
*/
int tile_selection_index_x = rand() % 2;
int tile_selection_index_y = 0;
float f_tx = tile_selection_index_x * tile_size_float;
float f_ty = tile_selection_index_y * tile_size_float;
sf::Vertex ver;
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top left corner
//ver.texCoords = sf::Vector2f( 0.f, 0.f);
ver.texCoords = sf::Vector2f(f_tx, f_ty);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top right corner
//ver.texCoords = sf::Vector2f( tile_size_float, 0.f);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom right corner
//ver.texCoords = sf::Vector2f( tile_size_float, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty + tile_size_float);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom left corner
//ver.texCoords = sf::Vector2f( 0.f, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx, f_ty + tile_size_float);
garr.append(ver);
}
void chunk_map::set_texture(sf::Texture t)
{
/*
Sets the texture data for this chunk map from the texture atlas.
*/
m_texture = t;
// TODO test this feature
// Attempt to optimize tearing on zooming to a different view.
//m_texture.setSmooth(true);
}
void chunk_map::set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y)
{
/*
Initialize the accordinates of the start of the chunk_map to the end.
*/
chunk_map::chunk_start_x = chunk_start_x;
chunk_map::chunk_start_y = chunk_start_y;
chunk_map::chunk_end_x = chunk_end_x;
chunk_map::chunk_end_y = chunk_end_y;
}
void chunk_map::draw(sf::RenderTarget& target, sf::RenderStates states)const
{
/*
The actual draw call to this specific chunk_map
*/
// position variables for this draw.
int left = 0;
int right = 0;
int top = 0;
int bottom = 0;
//get top left point of view
sf::Vector2f temp = target.getView().getCenter() - (target.getView().getSize() / 2.f);
//get top left point of view
left = static_cast<int>(temp.x / (chunksize * tilesize));
top = static_cast<int>(temp.y / (chunksize * tilesize));
//get bottom right point of view
temp += target.getView().getSize();
right = 1 + static_cast<int>(temp.x / (chunksize * tilesize));
bottom = 1 + static_cast<int>(temp.y / (chunksize * tilesize));
//clamp these to fit into array bounds:
left = std::max(0, std::min(left, tiles_per_chunk_x));
top = std::max(0, std::min(top, tiles_per_chunk_y));
right = std::max(0, std::min(right, tiles_per_chunk_x));
bottom = std::max(0, std::min(bottom, tiles_per_chunk_y));
//set texture and draw visible chunks:
states.texture = &m_texture;
for (int ix = left; ix < right; ++ix)
{
for (int iy = top; iy < bottom; ++iy)
{
target.draw(m_chunks[ix][iy], states);
}
}
}
tile_atlas.h
#pragma once
#include <SFML/Graphics/Texture.hpp>
class tile_atlas
{
private:
sf::Texture atlas_texture;
public:
tile_atlas();
~tile_atlas();
sf::Texture& get_atlas();
};
tile_atlas.cpp
#include "tile_atlas.h"
#include <iostream>
#include <string>
tile_atlas::tile_atlas()
{
std::string file_string = "tilemap_test.png";
if (!atlas_texture.loadFromFile(file_string))
{
std::cout << "Failed loading file: " << file_string << std::endl;
exit(1);
}
}
tile_atlas::~tile_atlas()
{
}
sf::Texture& tile_atlas::get_atlas()
{
return atlas_texture;
}
I am trying to fix this code to remove vertical artifacts so the above image will always look like this no matter if moving the view or zooming in/out.
[code for answer]
Using #Mario's answer this is the code I wrote (at the bottom of main.cpp) that completely fixed the artifacts.
here is a great link showing an example.
https://www.sfml-dev.org/tutorials/2.5/graphics-draw.php#off-screen-drawing
#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);
/*-----------------------------------------------------------*/
// Draw the texture
//rt.clear();
rt.draw(map.at(0));
rt.display();
if (cam.getSize().x < 500)
{
rt.setSmooth(false);
}
else
{
rt.setSmooth(true);
}
//// get the target texture (where the stuff has been drawn)
const sf::Texture& texture = rt.getTexture();
sf::Sprite sprite(texture);
app.draw(sprite);
//app.draw(map.at(0));
/*-----------------------------------------------------------*/
app.display();
Simple, yet effective:
Render your pixels 1:1 without scaling to a render texture and then upscale that instead.
Might be a bit tricky to determine the correct position, zoom, etc. but it can be done.

OpenCV 3d point projection

I'm having a problem righting an OpenCV program to project a 3d point. I seem to be running into this problem when using the projectPoints function of OpenCV.
Here is the error I got:
OpenCV Error: Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0)) in create, file /home/daniel/Comp4102/opencv/modules/core/src/matrix.cpp, line 2375
terminate called after throwing an instance of 'cv::Exception'
what(): /home/daniel/Comp4102/opencv/modules/core/src/matrix.cpp:2375: error: (-215) mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0) in function create
And here is the code that I wrote:
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <string>
std::vector<cv::Point3d> set3DPoints();
int main( int argc, char* argv[]) {
// Setting given variables.
double f = 500;
double sx = 1;
double sy = 1;
double ox = 320;
double oy = 240;
std::vector<cv::Point3d> objectPoints = set3DPoints();
cv::Mat Xw(1,3,cv::DataType<double>::type);
Xw.at<double>(0,0) = 150;
Xw.at<double>(0,1) = 200;
Xw.at<double>(0,2) = 350;
// Create the K matrix.
cv::Mat K(3,3,cv::DataType<double>::type);
K.at<double>(0,0) = -f/sx;
K.at<double>(1,0) = 0;
K.at<double>(2,0) = ox;
K.at<double>(0,1) = 0;
K.at<double>(1,1) = -f/sy;
K.at<double>(2,1) = oy;
K.at<double>(0,2) = 0;
K.at<double>(1,2) = 0;
K.at<double>(2,2) = 1;
// Creating the Rotation Matrix
cv::Mat R(3,3,cv::DataType<double>::type);
R.at<double>(0,0) = 1;
R.at<double>(1,0) = 0;
R.at<double>(2,0) = 0;
R.at<double>(0,1) = 0;
R.at<double>(1,1) = 1;
R.at<double>(2,1) = 0;
R.at<double>(0,2) = 0;
R.at<double>(1,2) = 0;
R.at<double>(2,2) = 1;
// Creating the Translation vector
cv::Mat T(3,1,cv::DataType<double>::type);
T.at<double>(0) = -70;
T.at<double>(1) = -95;
T.at<double>(2) = -120;
std::cout << "K: " << "\n" << K << "\n";
std::cout << "R: " << "\n" << R << "\n";
std::cout << "T: " << "\n" << T << "\n";
// Create zero distortion
cv::Mat distCoeffs(4,1,cv::DataType<double>::type);
distCoeffs.at<double>(0) = 0;
distCoeffs.at<double>(1) = 0;
distCoeffs.at<double>(2) = 0;
distCoeffs.at<double>(3) = 0;
// Creating Rodrigues rotation matrix
cv::Mat rvecR(3,1,cv::DataType<double>::type);
cv::Rodrigues(R,rvecR);
std::vector<cv::Point2f> projectedPoints;
cv::projectPoints(objectPoints, rvecR, T, K, distCoeffs, projectedPoints);
for(unsigned int i=0; i<projectedPoints.size(); i++){
std::cout << "Image point: " << objectPoints[i] << " Projected to " << projectedPoints[i] << "\n";
}
return 0;
}
std::vector<cv::Point3d> set3DPoints() {
std::vector<cv::Point3d> points;
double x,y,z;
x=150;
y=200;
z=350;
points.push_back(cv::Point3d(x,y,z));
return points;
}
The function projectPoints needs the arguments objectPoints and imagePoints of the same type, while you're passing objectPoints as Point3d, and imagePoints as Point2f.
The error is telling you that the two types are different: double != float.
Simply declare projectedPoints as Point2d, so that it has the same type as Point3d:
std::vector<cv::Point2d> projectedPoints;

Image processing : luminance weighted 2

I would like to weigh values of luminance on a new image.
I have an image (5px.jpg) of 5 pixels with these luminance :50,100,150,200,250.
I have a vector of coefficient.
I created a new Mat Z which combine luminance of 5px.jpg and the coefficient.
So, my first value of luminance is 50 (lum[0]=50) and I want it to be applied on the 5.1 (coef[0]=5.1) first pixel of my matrix. To do that, I need to weight the 6th pixel with the first and the second value of luminance. In my case,the luminance of my 6th pixel will be 95 because (0.1*50)+(0.9*100)=95
And so on...
But I do not know why my code does not works.
I had already asked a similar question for a vector here and now, I'm try to adapt to an image.
My picture in input :
My output :
#define MPI 3.14159265358979323846264338327950288419716939937510
#define RAD2DEG (180./MPI)
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cmath>
#include <math.h>
#include <string.h>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("5px.jpg", 1);
if (image.empty())
{
cout << "Couldn't load " << image << endl;
}
else
{
cout << "Image upload, go" << endl;
}
namedWindow("ImageIn", CV_WINDOW_AUTOSIZE);
imshow("ImageIn", image);
Mat imgGrayScale;
cvtColor(image, imgGrayScale, CV_BGR2GRAY);
float *deltaP = new float[imgGrayScale.cols];
float *angle = new float[imgGrayScale.cols];
float *coeff = new float[imgGrayScale.cols];
int col;
for (col = 0; col < imgGrayScale.cols; ++col)
{
//cout << "position x = " << col << endl;
deltaP[col] = imgGrayScale.at<uchar>(0, col);
//cout << "luminance = " << deltaP[col] << endl;
angle[col] = acos(deltaP[col] / 255);
//cout << "angle =" << angle[col] << endl;
coeff[col] = (1 / cos(angle[col]));
cout << "coeff = " << coeff[col] << endl;
}
int width = imgGrayScale.size().width;
int height = imgGrayScale.size().height;
int width2 = width * 5;
int idx_coef = 0;
Mat Z = Mat::zeros(height, width2, CV_8UC1);
//for (int r = 0; r < imgGrayScale.rows; r++)
//{
//cout << "Saut de ligne " << endl << endl << endl;
for (int t = 0; t < imgGrayScale.cols; t++)
{
//cout << "Saut de colonne " << endl;
// Attribue le coeff à une variable
int c = int(coeff[idx_coef]);
//cout << "x" << t << endl;
for (int i = 0; i < c; ++i)
{
Z.at<uchar>(0, c) = imgGrayScale.at<uchar>(0, t);
}
float alpha = fmod(coeff[idx_coef], 1.f);
float beta = 1.f - alpha;
Z.at<uchar>(0, c + 1) = (alpha * imgGrayScale.at<uchar>(0, t) + beta * imgGrayScale.at<uchar>(0, t + 1));
idx_coef++;
coeff[idx_coef] = coeff[idx_coef] - beta;
if (idx_coef >= width - 1)
{
int cc = int(coeff[idx_coef]);
for (int i = 0; i < cc; ++i)
{
Z.at<uchar>(0, c) = imgGrayScale.at<uchar>(0, t);
}
idx_coef = 0;
break;
}
}
//}
namedWindow("m", CV_WINDOW_AUTOSIZE);
imshow("m", Z);
imwrite("lumianacetest.jpg", Z);
int t = waitKey();
if ((char)t == 27)
return 0;
}
You messed up with the indices while accessing the matrix Z. You shoudn't access Z at column c, but you need access the current column (as a vector::push_back would do). So you can keep the current index column in a variable, here idx_z, and increment it every time you access Z
Here your Z is CV_8U, so you lose accuracy since your values are float. You can create Z as CV_32F, and if you need to store values in CV_8U format to save the image, you can convert to CV_8U later, eventually.
The last columns of Z won't be set to any value (so I initialized them with value 0). If you need them to have the last value as in the imgGrayScale, just decomment the relevant part of the code.
Here the code:
#define MPI 3.14159265358979323846264338327950288419716939937510
#define RAD2DEG (180./MPI)
#include <opencv2\opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
Mat1b imgGrayScale = (Mat1b(2, 5) << 50, 100, 150, 200, 250,
50, 100, 150, 200, 250);
vector<float> deltaP(imgGrayScale.cols);
vector<float> angle(imgGrayScale.cols);
vector<float> coeff(imgGrayScale.cols);
int col;
for (col = 0; col < imgGrayScale.cols; ++col)
{
//cout << "position x = " << col << endl;
deltaP[col] = imgGrayScale.at<uchar>(0, col);
//cout << "luminance = " << deltaP[col] << endl;
angle[col] = acos(deltaP[col] / 255);
//cout << "angle =" << angle[col] << endl;
coeff[col] = (1 / cos(angle[col]));
cout << "coeff = " << coeff[col] << endl;
}
int width = imgGrayScale.size().width;
int height = imgGrayScale.size().height;
int width2 = width * 5;
Mat1f Z(height, width2, 0.f);
for (int r = 0; r < imgGrayScale.rows; r++)
{
int idx_lum = 0;
int idx_coef = 0;
int idx_z = 0;
vector<float> coef = coeff;
// Set all values in Z to the last value in imgGrayScale
Z.row(r) = imgGrayScale(r, imgGrayScale.cols-1);
while (true)
{
int c = int(coef[idx_coef]);
for (int i = 0; i < c; ++i)
{
Z(r, idx_z++) = imgGrayScale(r, idx_lum);
}
float alpha = fmod(coef[idx_coef], 1.f);
float beta = 1.f - alpha;
Z(r, idx_z++) = (alpha * imgGrayScale(r, idx_lum) + beta * imgGrayScale(r, idx_lum + 1));
idx_coef++;
idx_lum++;
coef[idx_coef] = coef[idx_coef] - beta;
if (idx_lum >= imgGrayScale.cols - 1 || idx_coef >= coef.size() - 1)
{
int cc = int(coef[idx_coef]);
for (int i = 0; i < cc; ++i)
{
Z(r, idx_z++) = imgGrayScale(r, idx_lum);
}
idx_coef = 0;
break;
}
}
}
Mat1b ZZ;
Z.convertTo(ZZ, CV_8U);
cout << "Float values:" << endl;
cout << Z << endl << endl;
cout << "Uchar values:" << endl;
cout << ZZ << endl << endl;
namedWindow("m", CV_WINDOW_AUTOSIZE);
imshow("m", Z);
imwrite("lumianacetest.png", ZZ);
waitKey();
return 0;
}

Calculating 3D world point from 2D image point using OpenCV

I'm developing application for iOS. I'm using the camera matrix according to the book Mastering OpenCV.
In my scenario I have a well known box. I know its real dimensions and I know exactly its corner's pixels. Using this information I calculate the camera rotation and the translation vector.
From these parameters I'm able to calculate the camera position.
I'm checking my calculation by projecting the 3D world coordinate back to the image and I get very accurate results.
The world origin in my case is the middle of the bottom line of the box.
The box is open from one side. The image is taken in that direction, so I can see the content of the box.
Now, I have object in the box. I know very well image coordinate (2D) of the corners of this object. I know the real hight of the corner (the real Y and Y <> 0). How do I calculate the world X and Z of the corners of the object.
Here my code:
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>
using namespace cv;
using namespace std;
Point2f point;
vector<vector<Point2f>> objectPoints(1);
vector<vector<Point2f>> boxPoints(1);
Point3f calc3DPointOutOf2DwithYknown(double u, double v, float worldY, double fx, double fy, double cx, double cy, Mat tvec, Mat rotMat)
{
Point3f tmpPoint;
// This fiunction I need to complete
return tmpPoint;
}
int main( int argc, char** argv )
{
///////// Loading image
Mat sourceImage = imread("/Users/Ilan/Xcode/LK Test/LK Test/images/box_center640X480.jpg");
namedWindow( "Source", 1 );
///// Setting box corners /////
point = Point2f((float)102,(float)367.5); //640X480
boxPoints[0].push_back(point);
circle( sourceImage, boxPoints[0][0], 3, Scalar(0,255,0), -1, 8);
point = Point2f((float)83,(float)90.5); //640X480
boxPoints[0].push_back(point);
circle( sourceImage, boxPoints[0][1], 3, Scalar(0,255,0), -1, 8);
point = Point2f((float)520,(float)82.5); //640X480
boxPoints[0].push_back(point);
circle( sourceImage, boxPoints[0][2], 3, Scalar(0,255,0), -1, 8);
point = Point2f((float)510.5,(float)361); //640X480
boxPoints[0].push_back(point);
circle( sourceImage, boxPoints[0][3], 3, Scalar(0,255,0), -1, 8);
///// Setting object corners /////
point = Point2f((float)403.5,(float)250); //640X480
objectPoints[0].push_back(point);
circle( sourceImage, objectPoints[0][0], 3, Scalar(0,255,0), -1, 8);
point = Point2f((float)426.5,(float)251.5); //640X480
objectPoints[0].push_back(point);
circle( sourceImage, objectPoints[0][1], 3, Scalar(0,255,0), -1, 8);
imshow("Source", sourceImage);
vector<vector<Point3f>> worldBoxPoints(1);
Point3f tmpPoint;
tmpPoint = Point3f((float)-100,(float)0,(float)0);
worldBoxPoints[0].push_back(tmpPoint);
tmpPoint = Point3f((float)-100,(float)-150,(float)0);
worldBoxPoints[0].push_back(tmpPoint);
tmpPoint = Point3f((float)100,(float)-150,(float)0);
worldBoxPoints[0].push_back(tmpPoint);
tmpPoint = Point3f((float)100,(float)0,(float)0);
worldBoxPoints[0].push_back(tmpPoint);
std::cout << "There are " << boxPoints[0].size() << " roomPoints and " << worldBoxPoints[0].size() << " worldRoomPoints." << std::endl;
cv::Mat cameraMatrix1(3,3,cv::DataType<double>::type);
cv::setIdentity(cameraMatrix1);
cv::Mat distCoeffs1(4,1,cv::DataType<double>::type);
distCoeffs1.at<double>(0) = 0;
distCoeffs1.at<double>(1) = 0;
distCoeffs1.at<double>(2) = 0;
distCoeffs1.at<double>(3) = 0;
//Taken from Mastring OpenCV
double fx = 6.24860291e+02 * ((float)(sourceImage.cols)/352.);
double fy = 6.24860291e+02 * ((float)(sourceImage.rows)/288.);
double cx = (float)(sourceImage.cols)/2.;
double cy = (float)(sourceImage.rows)/2.;
cameraMatrix1.at<double>(0, 0) = fx;
cameraMatrix1.at<double>(1, 1) = fy;
cameraMatrix1.at<double>(0, 2) = cx;
cameraMatrix1.at<double>(1, 2) = cy;
std::cout << "After calib cameraMatrix --- 1: " << cameraMatrix1 << std::endl;
std::cout << "After calib distCoeffs: --- 1" << distCoeffs1 << std::endl;
cv::Mat rvec1(3,1,cv::DataType<double>::type);
cv::Mat tvec1(3,1,cv::DataType<double>::type);
cv::solvePnP(worldBoxPoints[0], boxPoints[0], cameraMatrix1, distCoeffs1, rvec1, tvec1);
std::cout << "rvec --- 1: " << rvec1 << std::endl;
std::cout << "tvec --- 1: " << tvec1 << std::endl;
cv::Mat rvecM1(3,3,cv::DataType<double>::type);
cv::Rodrigues(rvec1,rvecM1);
std::cout << "cameraRotation --- 1 : " << rvecM1 << std::endl;
std::cout << "cameraPosition --- 1 : " << (rvecM1.t())*((-1.0)*tvec1) << std::endl;
std::vector<cv::Point2f> projectedPoints1;
cv::projectPoints(worldBoxPoints[0], rvec1, tvec1, cameraMatrix1, distCoeffs1, projectedPoints1);
for(unsigned int i = 0; i < projectedPoints1.size(); ++i)
{
std::cout << "box point --- 1: " << boxPoints[0][i] << " Projected to --- 1: " << projectedPoints1[i] << std::endl;
}
vector<vector<Point3f>> worldObjectPoints(1);
tmpPoint = calc3DPointOutOf2DwithYknown(objectPoints[0][0].x, objectPoints[0][0].y, /*the real Y of the object*/ -40.0, fx, fy, cx, cy, tvec1, rvecM1);
worldObjectPoints[0].push_back(tmpPoint);
tmpPoint = calc3DPointOutOf2DwithYknown(objectPoints[0][1].x, objectPoints[0][1].y, /*the real Y of the object*/ -40.0, fx, fy, cx, cy, tvec1, rvecM1);
worldObjectPoints[0].push_back(tmpPoint);
cv::projectPoints(worldObjectPoints[0], rvec1, tvec1, cameraMatrix1, distCoeffs1, projectedPoints1);
for(unsigned int i = 0; i < projectedPoints1.size(); ++i)
{
std::cout << "object point --- 1: " << objectPoints[0][i] << " Projected to --- 1: " << projectedPoints1[i] << std::endl;
}
waitKey(0);
return 0;
}
So, I want to implement the calc3DPointOutOf2DwithYknown function. Of course the parameters are according to what I understand now. If I need other parameters I'll use others.
Thanks you so much,
Ilan
I succeed to solve it by myself. If it will help to any one, heres the code:
Point3f calc3DPointOutOf2DwithYknown(double u, double v, float worldY, double fx, double fy, double cx, double cy, Mat tvec, Mat rotMat)
{
Point3f tmpPoint;
float r1 = rotMat.at<double>(0,0);
float r2 = rotMat.at<double>(0,1);
float r3 = rotMat.at<double>(0,2);
float r4 = rotMat.at<double>(1,0);
float r5 = rotMat.at<double>(1,1);
float r6 = rotMat.at<double>(1,2);
float r7 = rotMat.at<double>(2,0);
float r8 = rotMat.at<double>(2,1);
float r9 = rotMat.at<double>(2,2);
float t1 = tvec.at<double>(0,0);
float t2 = tvec.at<double>(1,0);
float t3 = tvec.at<double>(2,0);
float xt = (u/fx) - (cx/fx);
float yt = (v/fy) - (cy/fy);
float K1 = xt*r8*worldY + xt*t3 - r2*worldY - t1;
float K2 = xt*r9 - r3;
float K3 = r1 - xt*r7;
float worldZ = (yt*r7*K1 + yt*K3*r8*worldY + yt*K3*t3 - r4*K1 - K3*r5*worldY - K3*t2)/
(r4*K2 + K3*r6 - yt*r7*K2 - yt*K3*r9);
float worldX = (K1 + worldZ*K2)/K3;
tmpPoint = Point3f(worldX, worldY, worldZ);
return tmpPoint;
}