Making a ray tracer and the code was failing so I decided to redo the whole thing and change the logic of the object but now for some reason, it keeps giving me an error and I've already tried editing it multiple times. ImageMagick give me an error saying that there isn't enough data to produce the ppm
other than the bit about the object the main logic how the ppm is produced hasn't changed much so I can't really figure out where the error is.
main.cpp
vec color(const ray& r, float t, vec a, vec centre)
{
vector <Light> lighting;
lighting.push_back(Light(vec(0, 0, 50), vec(0, 0, -1)));
vec totalLight{0, 0, 0};
for(int i = 0; i <lighting.size(); i++){
if(t > 0.0){
vec hit = unit_vector(r.p_at_par(t) - centre);
vec L = unit_vector(lighting[i].position() - r.p_at_par(t));
vec R = L - 2.0*dot(L, hit)*hit;
vec S = vec(1, 1, 1)*pow(max(0.f, dot(R, vec(0, 0, -1))), 50);//Specular component
vec D = (a * max(0.f, dot(L, hit)) * 1.0);//Diffuse component
totalLight += S + D;
return totalLight;
}
}
}
float clamp(float a)
{
return (a > 255)? 255: (a < 0)? 0: a;
}
int main()
{
const int w = 200, h = 100;
FILE *fp;
fp = fopen("img.ppm", "wb");
fprintf(fp, "P6\n%d %d\n255\n", w, h);
vec lower_corner(-2.0, -1.0, -1.0);
vec horizontal(4.0, 0.0, 0.0);
vec vertical(0.0, 2.0, 0.0);
vec origin(0.0, 0.0, 0.0);
vector <sphere> objects;
objects.push_back(sphere(vec(0,-100.5,-1), 100, vec(0, 1, 0)));
objects.push_back(sphere(vec(0, 0, -1), 0.5, vec(1, 0, 0)));
objects.push_back(sphere(vec(5, 5,-2), 3, vec(1, 0, 0)));
for(int j = h - 1; j >= 0; j--)
{
for(int i = 0; i < w; i++)
{
vec col(0, 0, 0);
static unsigned char pixel[3];
sphere* ClosestObject = NULL;
float u = float(i + random_double())/float(w);
float v = float(j + random_double())/float(h);
ray r(origin, lower_corner + u*horizontal + v*vertical);
float t = 0.0;
float t_near = 200000.0;
vec pixelColor(0.52 , 0.52 ,0.48);
for(int j = 0; j < objects.size(); j++)
{
if(t = objects[j].intersect(r))
{
if(t < t_near)
{
ClosestObject = &objects[j];
t_near = t;
}
}
if( t = 200000.0)
col = pixelColor;
else
col = color(r, t, ClosestObject->color, ClosestObject->centre);
pixel[0] = int(clamp(col.r() * 255));
pixel[1] = int(clamp(col.g() * 255));
pixel[2] = int(clamp(col.b() * 255));
fwrite(pixel, 3, 1, fp);
}
}
fclose(fp);
return 0;
}
}
Actually, a comment but too much text for that…
Your indentation is broken.
Hence, you didn't notice that the return 0; appears in the outer for loop, this one:
for(int j = h - 1; j >= 0; j--)
{
ends with:
fclose(fp);
return 0;
}
Additionally, the
fwrite(pixel, 3, 1, fp);
appears in the most inner loop
for (int j = 0; j < objects.size(); j++)
which is IMHO wrong as well.
So, the produced .ppm file claims to have w×h pixels but instead it provides w×objects.size() pixels.
If objects.size() < h (what I would expect) then you will have too less pixels in the .ppm file and ImageMagick will notice and complain.
Your source code, auto-formatted in my VS2017:
int main()
{
const int w = 200, h = 100;
FILE *fp;
fp = fopen("img.ppm", "wb");
fprintf(fp, "P6\n%d %d\n255\n", w, h);
vec lower_corner(-2.0, -1.0, -1.0);
vec horizontal(4.0, 0.0, 0.0);
vec vertical(0.0, 2.0, 0.0);
vec origin(0.0, 0.0, 0.0);
vector <sphere> objects;
objects.push_back(sphere(vec(0, -100.5, -1), 100, vec(0, 1, 0)));
objects.push_back(sphere(vec(0, 0, -1), 0.5, vec(1, 0, 0)));
objects.push_back(sphere(vec(5, 5, -2), 3, vec(1, 0, 0)));
for (int j = h - 1; j >= 0; j--)
{
for (int i = 0; i < w; i++)
{
vec col(0, 0, 0);
static unsigned char pixel[3];
sphere* ClosestObject = NULL;
float u = float(i + random_double()) / float(w);
float v = float(j + random_double()) / float(h);
ray r(origin, lower_corner + u * horizontal + v * vertical);
float t = 0.0;
float t_near = 200000.0;
vec pixelColor(0.52, 0.52, 0.48);
for (int j = 0; j < objects.size(); j++)
{
if (t = objects[j].intersect(r))
{
if (t < t_near)
{
ClosestObject = &objects[j];
t_near = t;
}
}
if (t = 200000.0)
col = pixelColor;
else
col = color(r, t, ClosestObject->color, ClosestObject->centre);
pixel[0] = int(clamp(col.r() * 255));
pixel[1] = int(clamp(col.g() * 255));
pixel[2] = int(clamp(col.b() * 255));
fwrite(pixel, 3, 1, fp);
}
}
fclose(fp);
return 0;
}
}
Please, check indentation and place closing curly-brackets correctly. Then it should work as before…
Related
I want to implement region growing algorithm for components Cr and Cb (YCbCr) (separate and combined) with manually chosen seed point (mouse click).
At the moment I have two functions that implement region growing for the H component in the HSV color space.
bool isOk(int new_x, int new_y, int width, int height)
{
if (new_x < 0 || new_y < 0 || new_x >= width || new_y >= height)
return false;
return true;
}
void lab04_MouseCallback(int event, int x, int y, int flags, void* param)
{
Mat* src = (Mat*)param;
int height = (*src).rows;
int width = (*src).cols;
if (event == CV_EVENT_LBUTTONDOWN)
{
printf("Seed point(x,y): %d,%d\n", x, y);
Mat labels = Mat::zeros((*src).size(), CV_16UC1);
int w = 3,
hue_avg = 0,
inf_x, sup_x,
inf_y, sup_y,
cnt = 0;
inf_x = (x - w < 0) ? 0 : x - w;
inf_y = (y - w < 0) ? 0 : y - w;
sup_x = (x + w >= width) ? (width - 1) : x + w;
sup_y = (y + w >= height) ? (height - 1) : y + w;
printf("inf x: %d sup x: %d --- inf y: %d sup y: %d\n", inf_x, sup_x, inf_y, sup_y);
for (int i = inf_y; i <= sup_y; ++i)
{
for (int j = inf_x; j <= sup_x; ++j)
{
hue_avg += (*src).data[i * width + j];
//printf("H at <%d, %d> is %d\n", i, j, (*src).data[i * width + j]);
}
}
hue_avg /= (sup_x - inf_x + 1) * (sup_y - inf_y + 1);
printf("Hue average: %d\n\n", hue_avg);
int k = 1, N = 1, hue_std = 10;
int konst = 3;
int T = konst * (float)hue_std;
queue<Point> Q;
Q.push(Point(x, y));
while (!Q.empty())
{
int dx[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
int dy[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
Point temp = Q.front();
Q.pop();
for (int dir = 0; dir < 8; ++dir)
{
int new_x = temp.x + dx[dir];
int new_y = temp.y + dy[dir];
if (isOk(new_x, new_y, width, height))
{
//printf("(%d, %d)\n", new_x, new_y);
if (labels.at<ushort>(new_y, new_x) == 0)
{
//printf("labels(%d, %d) = %hu\n", new_x, new_y, labels.at<ushort>(new_y, new_x));
if (abs((*src).at<uchar>(new_y, new_x) - hue_avg) < T)
{
//printf("this one\n");
Q.push(Point(new_x, new_y));
labels.at<ushort>(new_y, new_x) = k;
hue_avg = ((N * hue_avg) + (*src).at<uchar>(new_y, new_x)) / (N + 1);
++N;
}
}
}
}
}
Mat dst = (*src).clone();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (labels.at<ushort>(i, j) == 1)
{
dst.at<uchar>(i, j) = 255;
}
else
{
dst.at<uchar>(i, j) = 0;
}
}
}
imshow("dst", dst);
}
}
void lab04_MouseClick()
{
Mat src;
Mat hsv;
// Read image from file
char fname[MAX_PATH];
while (openFileDlg(fname))
{
src = imread(fname);
int height = src.rows;
int width = src.cols;
//Create a window
namedWindow("My Window", 1);
// Aplicare FTJ gaussian pt. eliminare zgomote: essential sa il aplicati
GaussianBlur(src, src, Size(5, 5), 0, 0);
// Componenta de culoare Hue a modelului HSV
Mat H = Mat(height, width, CV_8UC1);
// definire pointeri la matricea (8 biti/pixeli) folosita la stocarea
// componentei individuale H
uchar* lpH = H.data;
cvtColor(src, hsv, CV_BGR2HSV); // conversie RGB -> HSV
// definire pointer la matricea (24 biti/pixeli) a imaginii HSV
uchar* hsvDataPtr = hsv.data;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// index in matricea hsv (24 biti/pixel)
int hi = i * width * 3 + j * 3;
int gi = i * width + j; // index in matricea H (8 biti/pixel)
lpH[gi] = hsvDataPtr[hi] * 510 / 360; // lpH = 0 .. 255
}
}
//set the callback function for any mouse event
setMouseCallback("My Window", lab04_MouseCallback, &H);
//show the image
imshow("My Window", src);
// Wait until user press some key
waitKey(0);
}
}
How can I change this code to be for components Cr and Cb?
I'm trying to create my own CFD in C++. I have watched some videos on youtube about the Lattice Boltzmann method, but I cant get my simulations to look like the simulations performed in the videos with lattice Boltzmann implemented in Python.
I use SDL2 to create an image on my screen. I am not trying to create anything fast. Just something that will make pretty simulations on the CPU.
Here is my class for each cell:
//cell class
class cell {
public:
double Fi[nL] = {0,0,0,0,0,0,0,0,0};
double density = 0;
double momentumX = 0;
double momentumY = 0;
double velocityX = 0;
double velocityY = 0;
double Fieq[nL] = {0,0,0,0,0,0,0,0,0};
//obstacle
bool obstacle = false;
void densityOperator() {
for (int i = 0; i < nL; i++) {
density += Fi[i];
}
}
void momentumOperator() {
for (int i = 0; i < nL; i++) {
momentumX += Fi[i] * cX[i];
momentumY += Fi[i] * cY[i];
}
}
void velocityOperator() {
for (int i = 0; i < nL; i++) {
if (density == 0) {
density += 0.001;
}
velocityX += momentumX / density; // prolly very slow
velocityY += momentumY / density;
//velocityX += cX[i];
//velocityY += cY[i];
}
}
void FieqOperator() {
for (int i = 0; i < nL; i++) {
Fieq[i] = weights[i] * density *
(
1 +
(cX[i] * velocityX + cY[i] * velocityY) / Cs +
pow((cX[i] * velocityX + cY[i] * velocityY), 2) / (2 * pow(Cs, 4)) -
(velocityX * velocityX + velocityY * velocityY) / (2 * pow(Cs, 2))
);
}
}
void FiOperator() {
for (int i = 0; i < nL; i++) {
Fi[i] = Fi[i] - (timestep / tau) * (Fi[i] - Fieq[i]);
}
}
void addRightVelocity() {
Fi[0] = 1.f;
Fi[1] = 1.f;
Fi[2] = 1.f;
Fi[3] = 6.f;
Fi[4] = 1.f;
Fi[5] = 1.f;
Fi[6] = 1.f;
Fi[7] = 1.f;
Fi[8] = 1.f;
}
};
Please note that im am using a vector for my cells instead of a 2d array. I am using a index function to go from x,y to 1d cordinate.
int index(int x, int y) {
return x * nY + y;
}
Variables:
//box
const int nX = 400;
const int nY = 100;
//viscosity
float tau = 0.5; // 0.53
//time delta time per iteration
float timestep = 1;
//distance between cells
float dist = 1000;
//Speed of sound
float Cs = 1 / sqrt(3) * (dist / timestep);
//viscociti
float v = pow(Cs, 2) * (tau - timestep / 2); // tau will need to be much smaller
//time steps
int nT = 3000;
//lattice speeds and weights
const int nL = 9;
//Ci vector direction, discrete velocity
int cX[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
int cY[9] = { 0, 1, 1, 0, -1, -1, -1, 0 , 1 };
//weights, based on navier stokes
float weights[9] = { 4 / 9, 1 / 9, 1 / 36, 1 / 9, 1 / 36, 1 / 9, 1 / 36, 1 / 4, 1 / 36 };
//opposite populations
int cO[9] = { 0, 5, 6, 7, 8, 1, 2, 3, 4 };
My main function:
int main() {
//init vector cells
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
cell cellUnit;
cells.push_back(cellUnit);
TempCells.push_back(cellUnit);
}
}
//SDL
//SDL
//-------------------------------------------------------------
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(nX* 3, nY * 3, 0, &window, &renderer);
SDL_RenderSetScale(renderer, 3, 3);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
//-------------------------------------------------------------//
//Circle Object Gen
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
//cicle position
int circleX = 5;
int circleY = 50;
//circle radius
float radius = 10;
//distance bewtween cell and circle pos
float distance = sqrt(pow(circleX - x, 2) + pow(circleY - y, 2));
if (distance < radius) {
cells[index(x,y)].obstacle = true;
}
else {
cells[index(x, y)].obstacle = false;
}
}
}
//add velocity
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
cells[index(x, y)].addRightVelocity();
//random velocity
for (int i = 0; i < nL; i++) {
cells[index(x,y)].Fi[i] += (rand() % 200) / 100;
}
}
}
for (int t = 0; t < nT; t++) {
//SDL
//--------------------------------------------------------------
//clear renderer
if (t % 20 == 0) {
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
}
//--------------------------------------------------------------
//streaming:
//because we will loop over the same populations we do not want to switch the same population twice
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
if (x == 0) {
cells[index(x, y)].Fi[3] += 0.4;
}
//for populations
for (int i = 0; i < nL; i++) {
//boundary
//checs if cell is object or air
if (cells[index(x, y)].obstacle == false) {
//air
//targetet cell
int cellX = x + cX[i];
int cellY = y + cY[i];
//out of bounds check + rearange to other side
if (cellX < 0) {
//left to right
cellX = nX;
}
if (cellX >= nX) {
//right to left
cellX = 0;
continue;
}
if (cellY < 0) {
//top to buttom
cellY = nY;
}
if (cellY >= nY) {
//bottom to top
cellY = 0;
}
//if neighborinig cell is object --> collision with object
if (cells[index(cellX, cellY)].obstacle == true) {
//Boundary handling https://youtu.be/jfk4feD7rFQ?t=2821
TempCells[index(x,y)].Fi[cO[i]] = cells[index(x, y)].Fi[i];
}
//if not then stream to neighbor air cell with oposite population
TempCells[index(cellX, cellY)].Fi[cO[i]] = cells[index(x, y)].Fi[i];
}
else {
//wall
//SDL GRAPICHS
if (t % 20 == 0) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderDrawPoint(renderer, x, y);
}
}
}
}
}
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
for (int i = 0; i < nL; i++) {
cells[index(x, y)].Fi[i] = TempCells[index(x, y)].Fi[cO[i]];
}
}
}
//collision:
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
//density:
cells[index(x, y)].densityOperator();
//momentum:
cells[index(x, y)].momentumOperator();
//velocity:
cells[index(x, y)].velocityOperator();
//Fieq + new new Fi:
for (int i = 0; i < nL; i++) {
cells[index(x, y)].FieqOperator();
}
//SDL Graphics
if (t % 20 == 0) {
if (cells[index(x, y)].obstacle == false) {
SDL_SetRenderDrawColor(renderer, cells[index(x, y)].density, cells[index(x, y)].density , 255 , 255);
SDL_RenderDrawPoint(renderer, x, y);
}
}
}
}
for (int x = 0; x < nX; x++) {
for (int y = 0; y < nY; y++) {
cells[index(x, y)].FiOperator();
}
}
//SDL Graphics
if (t % 20 == 0 ) {
SDL_RenderPresent(renderer);
}
}
return 0;
}
I do realize my code might be a bit messy and not easy to understand at first. And it is definitely not optimal.
If anyone has any experience in programming their own LBM in c++ i would like to hear your input.
It seams like my simulations is working but i do not get those bueatiful animations like in, https://youtu.be/ZUXmO4hu-20?t=3394
Thanks for any help.
Edit:
I have edited my script to reset, density, velocity X Y and Momentum X Y
Simulation visualised by density, pink is higher, loops if density exceeds color range of 255
Simulation visualised by density
Simulation visualised by density
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I used aruco to build an AR project that uses four points to register //via the ICP algorithm. The point at which the marker is pasted is obtained by solving the tevc in the PNP. The constructed virtual object relies on the point of the VTK world coordinate system, but I got the wrong result, which I have not solved so far. The following is my core code.
I tested the transformation matrix separately and the coordinates I got, they seem to be correct
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
initTitle();
initBackGround();
initToolBar();
initConnect();
initTableRightMenu();
initTable();
//ui.toolRB->setVisible(true);
timer = new QTimer(this);
movingPoints.push_back(new PointSelf());
movingPoints.push_back(new PointSelf());
movingPoints.push_back(new PointSelf());
movingPoints.push_back(new PointSelf());
}
void MainWindow::normalSyle()
{
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
this->ui.openGLWidgetRB->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style);
this->ui.openGLWidgetRB->GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
}
void MainWindow::initTable()
{
ui.tableMeasure->setColumnCount(4);
ui.tableMeasure->setRowCount(8);
ui.tableMeasure->horizontalHeader()->setStyleSheet("QHeaderView::section {background-color:rgb(181, 184, 182);color: black;}");
ui.tableMeasure->horizontalHeader()->setDisabled(true);
ui.tableMeasure->setHorizontalHeaderLabels(QStringList() << "name" << "X" << "Y" << "Z");
ui.tableMeasure->setItem(0, 0, new QTableWidgetItem(QStringLiteral("markerId=0")));
ui.tableMeasure->setItem(1, 0, new QTableWidgetItem(QStringLiteral("markerId=1")));
ui.tableMeasure->setItem(2, 0, new QTableWidgetItem(QStringLiteral("markerId=2")));
ui.tableMeasure->setItem(3, 0, new QTableWidgetItem(QStringLiteral("markerId=3")));
ui.tableMeasure->setItem(4, 0, new QTableWidgetItem(QStringLiteral("markerId=4")));
ui.tableMeasure->setItem(5, 0, new QTableWidgetItem(QStringLiteral("markerId=5")));
ui.tableMeasure->setItem(6, 0, new QTableWidgetItem(QStringLiteral("Point1")));
ui.tableMeasure->setItem(7, 0, new QTableWidgetItem(QStringLiteral("Point2")));
}
double* MainWindow::dealPointPick()
{
QSize size;
size = this->ui.openGLWidgetRB->size();
double *picked = new double[3];
vtkSmartPointer<vtkCellPicker> cellPicker =
vtkSmartPointer<vtkCellPicker>::New();
cellPicker->SetTolerance(0.005);
cellPicker->Pick(rightClikPoint.x(), size.height() - rightClikPoint.y() - 1, 0, ui.openGLWidgetRB->GetRenderWindow()->GetRenderers()->GetFirstRenderer());
cellPicker->GetPickPosition(picked);
if (cellPicker->GetPointId() < 0) return nullptr;
return picked;
}
void MainWindow::dealMarkerId0()
{
double* position = dealPointPick();
pickedPoints.push_back(position);
if (position == nullptr) return;
for (int i = 0; i < 3; i++)
{
ui.tableMeasure->setItem(0, 1 + i, new QTableWidgetItem(QString::number(position[i])));
}
}
void MainWindow::dealMarkerId1()
{
double* position = dealPointPick();
pickedPoints.push_back(position);
if (position == nullptr) return;
for (int i = 0; i < 3; i++)
{
ui.tableMeasure->setItem(1, 1 + i, new QTableWidgetItem(QString::number(position[i])));
}
}
void MainWindow::dealMarkerId2()
{
double* position = dealPointPick();
pickedPoints.push_back(position);
if (position == nullptr) return;
for (int i = 0; i < 3; i++)
{
ui.tableMeasure->setItem(2, 1 + i, new QTableWidgetItem(QString::number(position[i])));
}
}
void MainWindow::dealMarkerId3()
{
double* position = dealPointPick();
pickedPoints.push_back(position);
if (position == nullptr) return;
for (int i = 0; i < 3; i++)
{
ui.tableMeasure->setItem(3, 1 + i, new QTableWidgetItem(QString::number(position[i])));
}
}
void MainWindow::openCamera()
{
capture.open(0);
capture.set(3, 1920);
capture.set(4, 1080);
if (!capture.isOpened())
{
cout << "camera is not open" << endl;
}
else
{
cout << "camera is open" << endl;
connect(timer, SIGNAL(timeout()), this, SLOT(updateWindow()));
timer->start(20);
}
}
Mat cameraMatrix(3, 3, cv::DataType<double>::type);
Mat distCoeffs(4, 1, cv::DataType<double>::type);
void MainWindow::updateWindow()
{
capture >> frame;
cameraMatrix.at<double>(0, 0) = 720;
cameraMatrix.at<double>(0, 1) = 0;
cameraMatrix.at<double>(0, 2) = 640;
cameraMatrix.at<double>(1, 0) = 0;
cameraMatrix.at<double>(1, 1) = 720;
cameraMatrix.at<double>(1, 2) = 360;
cameraMatrix.at<double>(2, 0) = 0;
cameraMatrix.at<double>(2, 1) = 0;
cameraMatrix.at<double>(2, 2) = 0;
distCoeffs.at<double>(0, 0) = 0;
distCoeffs.at<double>(1, 0) = 0;
distCoeffs.at<double>(2, 0) = 0;
distCoeffs.at<double>(3, 0) = 0;
cv::cvtColor(frame, image, COLOR_RGBA2GRAY);
aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejectPoint);
if (ids.size() > 0)
{
cv::aruco::drawDetectedMarkers(frame, corners, ids);
for (int i = 0; i < ids.size(); i++)
{
for (int j = 0; j < 4; j++)
{
circle(frame, Point(corners[i][j].x, corners[i][j].y), 3, Scalar(255, 0, 0));
}
std::vector<Point3f> objectPoints;
objectPoints.push_back(Point3f(-15, -15, 0));
objectPoints.push_back(Point3f(15, -15, 0));
objectPoints.push_back(Point3f(15, 15, 0));
objectPoints.push_back(Point3f(-15, 15, 0));
Mat rvec(3, 1, cv::DataType<double>::type);
Mat tvec(3, 1, cv::DataType<double>::type);
Mat rotationMatrix(3, 3, cv::DataType<double>::type);
Mat totM;
cv::solvePnP(objectPoints, corners[i], cameraMatrix, distCoeffs, rvec, tvec);
drawFrameAxes(frame, cameraMatrix, distCoeffs, rvec, tvec, 50);
if (ids[i] == 0)
{
Mat rvec0(3, 1, cv::DataType<double>::type);
Mat tvec0(3, 1, cv::DataType<double>::type);
Mat rotationMatrix0(3, 3, cv::DataType<double>::type);
Mat totM0;
cv::solvePnP(objectPoints, corners[i], cameraMatrix, distCoeffs, rvec0, tvec0);
drawFrameAxes(frame, cameraMatrix, distCoeffs, rvec0, tvec0, 50);
/*for (int i = 0; i < 3; i++)
{
double temp0 = tvec0.at<double>(i, 0);
movingPoints[0][i] = temp0;
}*/
movingPoints[0]->x = tvec0.at<double>(0, 0);
movingPoints[0]->y = tvec0.at<double>(1, 0);
movingPoints[0]->z = tvec0.at<double>(2, 0);
}
if (ids[i] == 1)
{
Mat rvec1(3, 1, cv::DataType<double>::type);
Mat tvec1(3, 1, cv::DataType<double>::type);
Mat rotationMatrix1(3, 3, cv::DataType<double>::type);
Mat totM1;
cv::solvePnP(objectPoints, corners[i], cameraMatrix, distCoeffs, rvec1, tvec1);
drawFrameAxes(frame, cameraMatrix, distCoeffs, rvec1, tvec1, 50);
movingPoints[1]->x = tvec1.at<double>(0, 0);
movingPoints[1]->y = tvec1.at<double>(1, 0);
movingPoints[1]->z = tvec1.at<double>(2, 0);
}
if (ids[i] == 2)
{
Mat rvec2(3, 1, cv::DataType<double>::type);
Mat tvec2(3, 1, cv::DataType<double>::type);
Mat rotationMatrix1(3, 3, cv::DataType<double>::type);
Mat totM2;
cv::solvePnP(objectPoints, corners[i], cameraMatrix, distCoeffs, rvec2, tvec2);
drawFrameAxes(frame, cameraMatrix, distCoeffs, rvec2, tvec2, 50);
movingPoints[2]->x = tvec2.at<double>(0, 0);
movingPoints[2]->y = tvec2.at<double>(1, 0);
movingPoints[2]->z = tvec2.at<double>(2, 0);
}
if (ids[i] == 3)
{
Mat rvec3(3, 1, cv::DataType<double>::type);
Mat tvec3(3, 1, cv::DataType<double>::type);
Mat rotationMatrix1(3, 3, cv::DataType<double>::type);
Mat totM3;
cv::solvePnP(objectPoints, corners[i], cameraMatrix, distCoeffs, rvec3, tvec3);
drawFrameAxes(frame, cameraMatrix, distCoeffs, rvec3, tvec3, 50);
movingPoints[3]->x = tvec3.at<double>(0, 0);
movingPoints[3]->y = tvec3.at<double>(1, 0);
movingPoints[3]->z = tvec3.at<double>(2, 0);
}
cv::Rodrigues(rvec, rotationMatrix);
camPointMatrix->Identity();
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
camPointMatrix->SetElement(i, j, rotationMatrix.at<double>(i, j));
}
camPointMatrix->SetElement(i, 3, tvec.at<double>(i, 0));
}
}
}
cv::cvtColor(image, frame, COLOR_RGBA2GRAY);
cv::imshow("image", frame);
cv::waitKey(10);`enter code here`
}
QString dirname;
vtkSmartPointer<vtkDICOMImageReader> dicomReader =
vtkSmartPointer< vtkDICOMImageReader>::New();
vtkSmartPointer<vtkSmartVolumeMapper> volumeMapper =
vtkSmartPointer<vtkSmartVolumeMapper>::New();
vtkSmartPointer<vtkVolumeProperty> volumeProperty =
vtkSmartPointer<vtkVolumeProperty>::New();
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
vtkSmartPointer<vtkPiecewiseFunction> volumeGradientOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
vtkSmartPointer<vtkColorTransferFunction> color =
vtkSmartPointer<vtkColorTransferFunction>::New();
vtkSmartPointer<vtkVolume> volume1 =
vtkSmartPointer<vtkVolume>::New();
void MainWindow::dicomImport()
{
dirname = QFileDialog::getExistingDirectory(this, "readDicom", "../CT");
if (dirname == "") return;
dicomReader->SetDataByteOrderToLittleEndian();
dicomReader->SetDirectoryName(dirname.toLatin1().data());
dicomReader->Update();
volumeMapper->SetInputData(dicomReader->GetOutput());
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->SetAmbient(0.4);
volumeProperty->SetDiffuse(0.6);
volumeProperty->SetSpecular(0.2);
compositeOpacity->AddPoint(120, 0.00);
compositeOpacity->AddPoint(200, 0.40);
compositeOpacity->AddPoint(1500, 0.60);
volumeProperty->SetScalarOpacity(compositeOpacity);
volumeGradientOpacity->AddPoint(100, 0.0);
volumeGradientOpacity->AddPoint(190, 0.5);
volumeGradientOpacity->AddPoint(300, 1.0);
color->AddRGBPoint(0.000, 0.00, 0.00, 0.00);
color->AddRGBPoint(64.00, 1.00, 0.52, 0.30);
color->AddRGBPoint(4000.0, 1.00, 1.00, 1.00);
color->AddRGBPoint(1200.0, 0.20, 0.20, 0.20);
volumeProperty->SetColor(color);
volume1->SetMapper(volumeMapper);
volume1->SetProperty(volumeProperty);
render->AddVolume(volume1);
render->ResetCamera();
render->GetActiveCamera()->ParallelProjectionOn();
render->ResetCameraClippingRange();
this->ui.openGLWidgetRB->GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
this->ui.openGLWidgetRB->GetRenderWindow()->Render();
}
void MainWindow::SVDRegistration()
{
double firstArrayPoints[3][4] = { 0.0 };
double OriginPoints[3][4] = { 0.0 };
double TargetPoint[3][4] = { 0.0 };
fixedPoints[4][3] = { 0.0 };
for (int i = 0; i < 4; i++)
{
fixedPoints[i][0] = pickedPoints[i][0];
fixedPoints[i][1] = pickedPoints[i][1];
fixedPoints[i][2] = pickedPoints[i][2];
}
for (int i = 0; i < 4; i++)
{
OriginPoints[0][i] = fixedPoints[i][0];
OriginPoints[1][i] = fixedPoints[i][1];
OriginPoints[2][i] = fixedPoints[i][2];
TargetPoint[0][i] = movingPoints[i]->x;
TargetPoint[1][i] = movingPoints[i]->y;
TargetPoint[2][i] = movingPoints[i]->z;
}
Eigen::MatrixXd OriginMatrix(3, 4);
Eigen::MatrixXd TargetMatrix(3, 4);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
OriginMatrix(i, j) = OriginPoints[i][j];
TargetMatrix(i, j) = TargetPoint[i][j];
}
}
double MassPointOrigin[3] = { 0.0 };
double MassPointTarget[3] = { 0.0 };
for (int i = 0; i < 4; i++)
{
MassPointOrigin[0] += OriginPoints[0][i];
MassPointOrigin[1] += OriginPoints[1][i];
MassPointOrigin[2] += OriginPoints[2][i];
MassPointTarget[0] += TargetPoint[0][i];
MassPointTarget[1] += TargetPoint[1][i];
MassPointTarget[2] += TargetPoint[2][i];
}
MassPointOrigin[0] = MassPointOrigin[0] / 4;
MassPointOrigin[1] = MassPointOrigin[1] / 4;
MassPointOrigin[2] = MassPointOrigin[2] / 4;
MassPointTarget[0] = MassPointTarget[0] / 4;
MassPointTarget[1] = MassPointTarget[1] / 4;
MassPointTarget[2] = MassPointTarget[2] / 4;
double OriginPointsAfterM[3][4] = { 0.0 };
double TargetPointAfterM[3][4] = { 0.0 };
for (int i = 0; i < 4; i++)
{
OriginPointsAfterM[0][i] = OriginPoints[0][i] - MassPointOrigin[0];
OriginPointsAfterM[1][i] = OriginPoints[1][i] - MassPointOrigin[1];
OriginPointsAfterM[2][i] = OriginPoints[2][i] - MassPointOrigin[2];
TargetPointAfterM[0][i] = TargetPoint[0][i] - MassPointTarget[0];
TargetPointAfterM[1][i] = TargetPoint[1][i] - MassPointTarget[1];
TargetPointAfterM[2][i] = TargetPoint[2][i] - MassPointTarget[2];
}
Eigen::MatrixXd MatrixOriginAM(3, 4);
Eigen::MatrixXd MatrixTarget(3, 4);
Eigen::MatrixXd MatrixTargetAM(4, 3);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
MatrixOriginAM(i, j) = OriginPointsAfterM[i][j];
MatrixTarget(i, j) = TargetPointAfterM[i][j];
}
}
MatrixTargetAM = MatrixTarget.transpose();
Eigen::MatrixXd WMatrix = MatrixOriginAM * MatrixTargetAM;
Eigen::JacobiSVD <Eigen::MatrixXd> svd(WMatrix, Eigen::ComputeThinU | Eigen::ComputeThinV);
Eigen::MatrixXd UMatrix = svd.matrixU();
Eigen::MatrixXd right_singular_vectors = svd.matrixV();
Eigen::MatrixXd VTMatrix = right_singular_vectors.transpose();
Eigen::MatrixXd RotationMatrix = UMatrix * VTMatrix;
double Rotate[3][3] = { 0.0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Rotate[i][j] = RotationMatrix(i, j);
}
}
Eigen::MatrixXd MassCentreOfTarget(3, 1);
Eigen::MatrixXd MassCentreOfOrigin(3, 1);
for (int i = 0; i < 3; i++)
{
MassCentreOfTarget(i, 0) = MassPointTarget[i];
MassCentreOfOrigin(i, 0) = MassPointOrigin[i];
}
Eigen::MatrixXd TranslationMatrix = MassCentreOfOrigin - RotationMatrix * MassCentreOfTarget;
double Translation[3] = { 0.0 };
for (int i = 0; i < 3; i++)
{
Translation[i] = TranslationMatrix(i, 0);
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
ReturnMatrix[i][j] = Rotate[i][j];
}
}
for (int i = 0; i < 3; i++)
{
ReturnMatrix[i][3] = Translation[i];
}
ReturnMatrix[3][3] = 1;
double deepCopyMatrix[16] = {0.0 };
for (int i = 0; i < 4; i++)
{
deepCopyMatrix[i * 4 + 0] = ReturnMatrix[i][0];
deepCopyMatrix[i * 4 + 1] = ReturnMatrix[i][1];
deepCopyMatrix[i * 4 + 2] = ReturnMatrix[i][2];
deepCopyMatrix[i * 4 + 3] = ReturnMatrix[i][3];
}
transMatrix->DeepCopy(deepCopyMatrix);
volume1->SetUserMatrix(transMatrix);
render->AddVolume(volume1);
render->Render();
this->ui.openGLWidgetRB->GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
this->ui.openGLWidgetRB->GetRenderWindow()->Render();
}
void MainWindow::stlImport()
{
stlReader = vtkSmartPointer<vtkSTLReader>::New();
QString filename;
filename = QFileDialog::getOpenFileName(this, QStringLiteral("��ȡSTL"), "../", "*.stl;*./STL");
if (filename == "") return;
stlReader->SetFileName(filename.toUtf8().data());
stlReader->Update();
displayClipData(stlReader->GetOutput());
}
void MainWindow::displayClipData(vtkPolyData *input)
{
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(input);
mapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(1.0, 1.0, 1.0);
actor->GetProperty()->SetSpecular(0.5);
actor->VisibilityOn();
render->AddActor(actor);
//render->SetBackground(0.157, 0.157, 0.157);
render->ResetCamera();
render->GetActiveCamera()->ParallelProjectionOn();
render->ResetCameraClippingRange();
this->ui.openGLWidgetRB->GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
this->ui.openGLWidgetRB->GetRenderWindow()->Render();
}
Kindly help me with the working of Distance transform and rectify the errors. I have tried Borgefors' method which has defined values for Eucledian measure. I get all zeros as output.
Below is the code which i have tried.
int _tmain(int argc, _TCHAR* argv[])
{
Mat v = imread("ref.png", 0);
imshow("input", v);
Mat forward = (Mat_<uchar>(5, 5) << 0, 11, 0, 11, 0, 11, 7, 5, 7, 11, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Mat backward = (Mat_<uchar>(5, 5) << 0,0,0,0,0, 0,0,0,0,0, 0, 0, 0, 5, 0, 11, 7, 5, 7, 11, 0, 11, 0, 11, 0);
Mat op = cv::Mat::zeros(v.size(), CV_32FC1);
cout << forward;
cout << backward;
int r = v.rows;
int c = v.cols;
float min=100, x = 0;
int size = 3;
int lim = size / 2;
int a, b;
for (int i = lim; i <= r-1-lim; i++)
{
for (int j = lim; j <= c-1-lim; j++)
{
for (int k = -lim; k <= lim; k++)
{
for (int l = -lim; l <= lim; l++)
{
a = (v.at<uchar>(i + k, j + l));
b=(forward.at<uchar>(k + lim, l + lim));
x = a + b;
if (x>0 && min> x)
min = x;
}
}
op.at<float>(i, j) = min;
}
}
cout << min;
for (int i = (r-1-lim); i >lim; i--)
{
for (int j = (c-1-lim); j >lim; j--)
{
for (int k = -lim; k <= lim; k++)
{
for (int l = -lim; l <= lim; l++)
{
a = (v.at<uchar>(i + k, j + l));
b = (forward.at<uchar>(k + lim, l + lim));
x = a + b;
if (x >0 && min> x) min = x;
}
}
op.at<float>(i, j) = min;
}
}
cout << op;
Mat res = cv::Mat::ones(v.size(), CV_8UC1);
normalize(op, res, 0, 255, NORM_MINMAX);
imshow("output",res);
waitKey(0);
return 0;
}
Which is the best method and why it is the best way to implement Distance Transform?
Here is how to fix your code:
Apply the backward mask in the backward loop, you apply the same mask there as in the forward loop.
Use only the defined weights, the values in the mask where you wrote 0 are not part of the mask. Those pixels don't have a distance of 0!
As for your second question, it's probably out of scope for SO. But what the best method is depends very much on the goal. You have a fast and relatively accurate method here, there are other methods that are exact but more expensive.
I'm trying to program a simple animation using GLUT and OpenGL in c++. I've created three functions for this purpose: catSpline(), fillArray(), and fixedAngle(). catSpline() returns a GLfloat value, fillArray() is a void function that consists of a series of loops that fills a series of arrays with GLfloat values produced using catSpline, and fixedAngle() will return a 16-unit array. Here is the code for these three methods:
GLfloat * fixedAngle(GLfloat initialX, GLfloat initialY, GLfloat initialZ, GLfloat rotX, GLfloat rotY, GLfloat rotZ)
{
ArrayXXf z(4,4); //initializing the 4x4 rotation matrixes
ArrayXXf y(4,4);
ArrayXXf x(4,4);
x<<1, 0, 0, 0,
0, cos(rotX), -sin(rotX), 0,
0, sin(rotX), cos(rotX), 0,
0, 0, 0, 1;
y<<cos(rotY), 0, sin(rotY), 0,
0, 1, 0, 0,
-sin(rotY), 0, cos(rotY), 0,
0, 0, 0, 1;
z<< cos(rotZ), -sin(rotZ), 0, 0,
sin(rotZ), cos(rotZ), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
ArrayXXf fin(4,4);
fin = x * y * z;
fin(0,3) = initialX;
fin(1,3) = initialY;
fin(2,3) = initialZ;
//now we've moved the translational information into the final matrix
// std::cout << fin;
fin(3,3) = 1;
GLfloat * arr;
arr = (GLfloat *) malloc(16*sizeof(GLfloat));
arr[0] = fin(0,0);
arr[1] = fin(0,1);
arr[2] = fin(0,2);
arr[3] = fin(0,3);
arr[4] = fin(1,0);
arr[5] = fin(1,1);
arr[6] = fin(1,2);
arr[7] = fin(1,3);
arr[8] = fin(2,0);
arr[9] = fin(2,1);
arr[10] = fin(2,2);
arr[11] = fin(2,3);
arr[12] = fin(3,0);
arr[13] = fin(3,1);
arr[14] = fin(3,2);
arr[15] = fin(3,3);
return arr;
}
GLfloat catSpline(GLfloat x1, GLfloat x2, GLfloat x3, GLfloat x4, GLfloat t)
{
ArrayXXf M(4,4); //4x4 M matrix
ArrayXXf P(4,1); //matrix to hold keyframe x values
P(0,0) = x1;
P(1,0) = x2;
P(2,0) = x3;
P(3,0) = x4;
//keyframe x values
M(0,0) = -0.5;
M(0,1) = 2-(-0.5);
M(0,2) = -0.5-2;
M(0,3) = 0.5;
M(1,0) = 2*0.5;
M(1,1) = 0.5-3;
M(1,2) = 3-(2*0.5);
M(1,3) = -0.5;
M(2,0) = -0.5;
M(2,1) = 0;
M(2,2) = 0.5;
M(2,3) = 0;
M(3,0) = 0;
M(3,1) = 1;
M(3,2)=0;
M(3,3)=0;
ArrayXXf T(1,4);
T(0,0) = t*t*t; //you can't cube a float, but you can get the same result by doing this
T(0,1) = t*t;
T(0,2) = t;
T(0,3)=1;
//now the T matrix is filled
ArrayXXf TM(1,4);
TM(0,0) = (T(0,0) * M(0,0)) + (T(0,1) * M(1,0)) + (T(0,2) * M(2,0)) + (T(0,3) * M(0,3));
TM(0,1) = (T(0,0) * M(0,1)) + (T(0,1) * M(1,1)) + (T(0,2) * M(2,1)) + (T(0,3) * M(3,1));
TM(0,2) = (T(0,0) * M(0,2)) + (T(0,1) * M(1,2)) + (T(0,2) * M(2,2)) + (T(0,3) * M(3,2));
TM(0,3) = (T(0,0) * M(0,3)) + (T(0,1) * M(1,3)) + (T(0,2) * M(2,3)) + (T(0,3) * M(3,3));
//first multiply T amd M
GLfloat TMP;
TMP = (TM(0,0) * P(0,0)) + (TM(0,1) *P(1,0)) + (TM(0,2) * P(2,0)) + (TM(0,3) * P(3,0));
return TMP;
}
void fillArrays()
{
/* zRot = catSpline(2, 4, 5, 6);
yRot = catSpline(1, 4, 6, 7);
xRot = catSpline(6, 3, 2, 6);
xArr = catSpline(9, 4, 3, 10);
yArr = catSpline(1, 2, 4, 8);
zArr = catSpline(8, 3, 1, 3);*/
for(int j=0; j>=100; j++)
{
xArr[j] = catSpline(2, 4, 5, 6, t);
t+=0.1;
}
for(int i=0; i>=100; i++)
{
yArr[i] = catSpline(2, 4, 5, 6, ty);
ty+=0.1;
}
for(int k=0; k>=100; k++)
{
xArr[k] = catSpline(2, 4, 5, 6, tz);
tz += 0.1;
}
for(int a=0; a>=100; a++)
{
xRot[a] = catSpline(2, 4, 5, 6, rx);
rx += 0.1;
}
for(int b=0; b>=100; b++)
{
yRot[b] = catSpline(2, 4, 5, 6, ry);
rz += 0.1;
}
for(int c=0; c>=100; c++)
{
zRot[c] = catSpline(2, 4, 5, 6, rz);
rz += 0.1;
}
}
The way I use these three functions is in a loop called Render, I set up OpenGL for displaying an animation of a teapot model, call fillArrays(), and then attempt to store the result of a single fixedAngle call (using a few entries form the arrays filled in just before) in a new array called foo. This seems to be the cause of the errors, with foo only containing a pointer address rather than pointing to the actual array so I can use it. This is the code I'm using to call these functions:
fillArrays();
GLfloat * foo;
foo = (GLfloat *) malloc(16*sizeof(GLfloat));
foo = fixedAngle(xArr[tp], yArr[tp], zArr[tp], xRot[tp], yRot[tp], zRot[tp]);
glLoadMatrixf(foo);
After having used multiple print statements to print out the results of my functions, I know that the problem has to be how I set up the pointers somewhere. Can anyone help me return the array correctly?
Please note: if some of the matrix syntax seems unfammiliar, it's because I'm using a c++ library called Eigen to do some of the matrix math. Once again, after having rigorously printed out the results of the functions, I know that the functions that use Eigen syntax are producing the right values.
You can replace...
GLfloat * arr;
arr = (GLfloat *) malloc(16*sizeof(GLfloat));
...with...
std::vector<GLfloat> arr(16);
...or even directly initialise it instead of copying elements afterwards...
std::vector<GLfloat> arr { fin(0,0), fin(0,1), fin(0,2), fin(0,3),
fin(1,0), fin(1,1), fin(1,2), fin(1,3),
fin(2,0), fin(2,1), fin(2,2), fin(2,3),
fin(3,0), fin(3,1), fin(3,2), fin(3,3) };
...which - FWIW - could also be done like this...
std::vector<GLfloat> arr;
for (int a = 0; a <= 3; ++a)
for (int b = 0; b <= 3; ++b)
arr.push_back(fin(a,b));
With any of the above, you'll need to change the return type correspondingly...
std::vector<GLfloat> fixedAngle(
GLfloat initialX, GLfloat initialY, GLfloat initialZ,
GLfloat rotX, GLfloat rotY, GLfloat rotZ)
{
...
...then you can call fixedAngle and use foo like this:
fillArrays();
std::vector<GLfloat> foo = fixedAngle(xArr[tp], yArr[tp], zArr[tp],
xRot[tp], yRot[tp], zRot[tp]);
glLoadMatrixf(foo.data()); // or `&foo[0]` if you prefer...