diff --git a/.vscode/settings.json b/.vscode/settings.json index 5b09250..d3930e2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,9 @@ "python.pythonPath": "python_venv\\Scripts\\python.exe", "python.formatting.provider": "black", "files.associations": { - "xiosbase": "cpp" + "xiosbase": "cpp", + "vector": "cpp", + "xutility": "cpp", + "*.inc": "cpp" } } \ No newline at end of file diff --git a/C++/DifferentiableRenderer.h b/C++/DifferentiableRenderer.h index 9140bfb..925ddb8 100644 --- a/C++/DifferentiableRenderer.h +++ b/C++/DifferentiableRenderer.h @@ -47,12 +47,6 @@ using namespace std; _b_ = _c_; \ } -void get_edge_xrange_from_ineq(double ineq[12], int width, int y, int &x_begin, int &x_end); -inline void render_part_interpolated(double *image, double *z_buffer, int y_begin, int x_min, int x_max, int y_end, bool strict_edge, double *xy1_to_A, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, bool perspective_correct); -inline void render_part_interpolated_B(double *image, double *image_B, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_A, double *xy1_to_A_B, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, bool perspective_correct); -inline void render_part_textured_gouraud(double *image, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_UV, double *xy1_to_L, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, double *Texture, int *Texture_size, bool perspective_correct); -inline void render_part_textured_gouraud_B(double *image, double *image_B, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_UV, double *xy1_to_UV_B, double *xy1_to_L, double *xy1_to_L_B, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, double *Texture, double *Texture_B, int *Texture_size, bool perspective_correct); - struct Scene { unsigned int *faces; @@ -89,6 +83,88 @@ struct Scene bool integer_pixel_centers; }; +template +class Image +{ +public: + T *data; + int nb_channels; + int width; + int height; + + Image() : width(0), height(0), nb_channels(0), data(nullptr) + { /* empty image */ + } + Image(const int &_w, const int &_h, const int &_nb_channels, T *_data) : width(_w), height(_h), nb_channels(_nb_channels), data(_data) + { + } + inline void writePixel(int x, int y, T *color) + { + int indx = y * width + x; + for (int k = 0; k < nb_channels; k++) + data[nb_channels * indx + k] = color[k]; + } + inline void writePixelTransparent(int x, int y, T *color, double alpha) + { + int indx = y * width + x; + for (int k = 0; k < nb_channels; k++) + { + data[nb_channels * indx + k] *= alpha; + data[nb_channels * indx + k] += (1 - alpha) * color[k]; + } + } +}; + +template +class Fragments +{ + // class used to keep track of pixel writes +public: + std::vector list_x; + std::vector list_y; + std::vector list_values; + std::vector list_alpha; + int nb_channels; + int width; + int height; + Fragments() : width(0), height(0), nb_channels(0) + { /* empty image */ + } + Fragments( + const int &_w, + const int &_h, + const int &_nb_channels) : width(_w), + height(_h), + nb_channels(_nb_channels) + { + } + + inline void writePixel(int x, int y, T *color) + { + for (int k = 0; k < nb_channels; k++) + list_values.push_back(color[k]); + list_x.push_back(x); + list_y.push_back(y); + list_alpha.push_back(1); + } + inline void writePixelTransparent(int x, int y, T *color, double alpha) + { + for (int k = 0; k < nb_channels; k++) + list_values.push_back(color[k]); + list_x.push_back(x); + list_y.push_back(y); + list_alpha.push_back(alpha); + } +}; + +using FragmentsDouble = Fragments; + +void get_edge_xrange_from_ineq(double ineq[12], int width, int y, int &x_begin, int &x_end); +inline void render_part_interpolated(double *image, double *z_buffer, int y_begin, int x_min, int x_max, int y_end, bool strict_edge, double *xy1_to_A, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, bool perspective_correct); +inline void render_part_interpolated_B(double *image, double *image_B, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_A, double *xy1_to_A_B, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, bool perspective_correct); +inline void render_part_textured_gouraud(double *image, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_UV, double *xy1_to_L, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, double *Texture, int *Texture_size, bool perspective_correct); +inline void render_part_textured_gouraud_B(double *image, double *image_B, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_UV, double *xy1_to_UV_B, double *xy1_to_L, double *xy1_to_L_B, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, double *Texture, double *Texture_B, int *Texture_size, bool perspective_correct); + void inv_matrix_3x3(double *S, double *T) { // S= |S[0] S[1] S[2]| @@ -738,8 +814,8 @@ void get_triangle_stencil_equations(double Vxy[][2], double bary_to_xy1[9], doub } } -template -void rasterize_triangle_interpolated(double Vxy[][2], double Zvertex[3], T *Avertex[], double z_buffer[], T image[], int height, int width, int sizeA, bool strict_edge, bool perspective_correct) +template +void rasterize_triangle_interpolated(double Vxy[][2], double Zvertex[3], T *Avertex[], double z_buffer[], ImageType &image, int height, int width, int sizeA, bool strict_edge, bool perspective_correct) { int y_begin[2], y_end[2]; @@ -905,14 +981,17 @@ inline void get_xrange(int width, const double *left_eq, const double *right_eq, } } -inline void render_part_interpolated(double *image, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_A, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, bool perspective_correct) +template +inline void render_part_interpolated(ImageType &image, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_A, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, bool perspective_correct) { double t[3]; double *A0y; + double *color; double Z0y; short int x_begin, x_end; double Z; A0y = new double[sizeA]; + color = new double[sizeA]; if (y_begin < 0) { @@ -949,7 +1028,9 @@ inline void render_part_interpolated(double *image, double *z_buffer, int x_min, { z_buffer[indx] = Z; for (short int k = 0; k < sizeA; k++) - image[sizeA * indx + k] = (A0y[k] + xy1_to_A[3 * k] * x) * Z; + color[k] = (A0y[k] + xy1_to_A[3 * k] * x) * Z; + + image.writePixel(x, y, color); } indx++; } @@ -962,7 +1043,8 @@ inline void render_part_interpolated(double *image, double *z_buffer, int x_min, { z_buffer[indx] = Z; for (short int k = 0; k < sizeA; k++) - image[sizeA * indx + k] = A0y[k] + xy1_to_A[3 * k] * x; + color[k] = A0y[k] + xy1_to_A[3 * k] * x; + image.writePixel(x, y, color); } indx++; } @@ -1039,23 +1121,16 @@ inline void render_part_interpolated_B(double *image, double *image_B, double *z delete[] A0y_B; } -template -void rasterize_triangle_textured_gouraud(double Vxy[][2], double Zvertex[3], double UVvertex[][2], double ShadeVertex[], double z_buffer[], T image[], int height, int width, int sizeA, T *Texture, int *Texture_size, bool strict_edge, bool perspective_correct) +void compute_textured_gouraud_mapping_matrices( + double xy1_to_bary[9], + double xy1_to_UV[6], + double xy1_to_L[3], + double xy1_to_Z[3], + double Zvertex[3], + double UVvertex[3][2], + double ShadeVertex[3], + bool perspective_correct) { - int y_begin[2], y_end[2]; - - double edge_eq[3][3]; - double bary_to_xy1[9]; - double xy1_to_bary[9]; - double xy1_to_UV[6]; - double xy1_to_L[3]; - double xy1_to_Z[3]; - int left_edge_id[2], right_edge_id[2]; - int x_min, x_max; - - // compute triangle borders equations - - get_triangle_stencil_equations(Vxy, bary_to_xy1, xy1_to_bary, edge_eq, strict_edge, x_min, x_max, y_begin, y_end, left_edge_id, right_edge_id); // create matrices that map image coordinates to attributes A and depth z if (perspective_correct) @@ -1086,7 +1161,37 @@ void rasterize_triangle_textured_gouraud(double Vxy[][2], double Zvertex[3], dou xy1_to_UV[3 * i + j] += UVvertex[k][i] * xy1_to_bary[k * 3 + j]; } } +} + +template +void rasterize_triangle_textured_gouraud(double Vxy[][2], double Zvertex[3], double UVvertex[][2], double ShadeVertex[], double z_buffer[], ImageType &image, int height, int width, int sizeA, T *Texture, int *Texture_size, bool strict_edge, bool perspective_correct) +{ + int y_begin[2], y_end[2]; + double edge_eq[3][3]; + double bary_to_xy1[9]; + double xy1_to_bary[9]; + double xy1_to_UV[6]; + double xy1_to_L[3]; + double xy1_to_Z[3]; + int left_edge_id[2], right_edge_id[2]; + int x_min, x_max; + + // compute triangle borders equations + get_triangle_stencil_equations(Vxy, bary_to_xy1, xy1_to_bary, edge_eq, strict_edge, x_min, x_max, y_begin, y_end, left_edge_id, right_edge_id); + + // create matrices that map image coordinates to attributes A and depth z + compute_textured_gouraud_mapping_matrices( + xy1_to_bary, + xy1_to_UV, + xy1_to_L, + xy1_to_Z, + Zvertex, + UVvertex, + ShadeVertex, + perspective_correct); + + //Image image2(width, height, sizeA, image); for (int k = 0; k < 2; k++) render_part_textured_gouraud(image, z_buffer, x_min, x_max, y_begin[k], y_end[k], strict_edge, xy1_to_UV, xy1_to_L, xy1_to_Z, edge_eq[left_edge_id[k]], edge_eq[right_edge_id[k]], width, height, sizeA, Texture, Texture_size, perspective_correct); } @@ -1156,7 +1261,8 @@ void rasterize_triangle_textured_gouraud_B(double Vxy[][2], double Vxy_B[][2], d Vxy_B[v][d] += bary_to_xy1_B[3 * d + v]; } -inline void render_part_textured_gouraud(double *image, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_UV, double *xy1_to_L, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, double *Texture, int *Texture_size, bool perspective_correct) +template +inline void render_part_textured_gouraud(ImageType &image, double *z_buffer, int x_min, int x_max, int y_begin, int y_end, bool strict_edge, double *xy1_to_UV, double *xy1_to_L, double *xy1_to_Z, double *left_eq, double *right_eq, int width, int height, int sizeA, double *Texture, int *Texture_size, bool perspective_correct) { double t[3]; double L0y; @@ -1164,9 +1270,11 @@ inline void render_part_textured_gouraud(double *image, double *z_buffer, int x_ short int x_begin, x_end; double Z; double *A; + double *color; double UV0y[2]; A = new double[sizeA]; + color = new double[sizeA]; if (y_begin < 0) { @@ -1221,9 +1329,14 @@ inline void render_part_textured_gouraud(double *image, double *z_buffer, int x_ UV[k] = (UV0y[k] + xy1_to_UV[3 * k] * x) * Z; bilinear_sample(A, Texture, Texture_size, UV, sizeA); - for (int k = 0; k < sizeA; k++) - image[sizeA * indx + k] = A[k] * L; + color[k] = A[k] * L; + + image.writePixel(x, y, color); + // for (int k = 0; k < sizeA; k++) + // { + // image[sizeA * indx + k] = color[k]; + // } } indx++; } @@ -1248,7 +1361,13 @@ inline void render_part_textured_gouraud(double *image, double *z_buffer, int x_ bilinear_sample(A, Texture, Texture_size, UV, sizeA); for (int k = 0; k < sizeA; k++) - image[sizeA * indx + k] = A[k] * L; + color[k] = A[k] * L; + + image.writePixel(x, y, color); + // for (int k = 0; k < sizeA; k++) + // { + // image[sizeA * indx + k] = color[k]; + // } } indx++; } @@ -1539,7 +1658,7 @@ void get_edge_stencil_equations_B(double Vxy[][2], double Vxy_B[][2], double sig } template -void rasterize_edge_interpolated(double Vxy[][2], Te image[], Te *Avertex[], double z_buffer[], double Zvertex[], int height, int width, int sizeA, double sigma, bool clockwise, bool perspective_correct) +void rasterize_edge_interpolated(double Vxy[][2], Image image, Te *Avertex[], double z_buffer[], double Zvertex[], int height, int width, int sizeA, double sigma, bool clockwise, bool perspective_correct) { double xy1_to_bary[6]; double xy1_to_transp[3]; @@ -1589,6 +1708,8 @@ void rasterize_edge_interpolated(double Vxy[][2], Te image[], Te *Avertex[], dou { // Line rasterization setup for interpolated values double t[3]; double T0y, Z0y; + double *A; + A = new double[sizeA]; t[0] = 0; t[1] = y; @@ -1616,10 +1737,9 @@ void rasterize_edge_interpolated(double Vxy[][2], Te image[], Te *Avertex[], dou for (short int k = 0; k < sizeA; k++) { - image[sizeA * indx + k] *= T; - double A = (A0y[k] + xy1_to_A[3 * k] * x) * Z; - image[sizeA * indx + k] += (1 - T) * A; + A[k] = (A0y[k] + xy1_to_A[3 * k] * x) * Z; } + image.writePixelTransparent(x, y, A, T); } indx++; } @@ -1632,13 +1752,11 @@ void rasterize_edge_interpolated(double Vxy[][2], Te image[], Te *Avertex[], dou if (Z < z_buffer[indx]) { double T = T0y + T_inc * x; - for (short int k = 0; k < sizeA; k++) { - image[sizeA * indx + k] *= T; - double A = (A0y[k] + xy1_to_A[3 * k] * x); - image[sizeA * indx + k] += (1 - T) * A; + A[k] = (A0y[k] + xy1_to_A[3 * k] * x); } + image.writePixelTransparent(x, y, A, T); } indx++; } @@ -1779,7 +1897,7 @@ void rasterize_edge_interpolated_B(double Vxy[][2], double Vxy_B[][2], Te image[ } template -void rasterize_edge_textured_gouraud(double Vxy[][2], double Zvertex[2], double UVvertex[][2], double ShadeVertex[2], double z_buffer[], Te image[], int height, int width, int sizeA, Te *Texture, int *Texture_size, double sigma, bool clockwise, bool perspective_correct) +void rasterize_edge_textured_gouraud(double Vxy[][2], double Zvertex[2], double UVvertex[][2], double ShadeVertex[2], double z_buffer[], Image image, int height, int width, int sizeA, Te *Texture, int *Texture_size, double sigma, bool clockwise, bool perspective_correct) { double xy1_to_bary[6]; double xy1_to_transp[3]; @@ -1790,8 +1908,10 @@ void rasterize_edge_textured_gouraud(double Vxy[][2], double Zvertex[2], double double xy1_to_L[3]; double *A; double UV0y[2]; + double *color; A = new double[sizeA]; + color = new double[sizeA]; get_edge_stencil_equations(Vxy, height, width, sigma, xy1_to_bary, xy1_to_transp, ineq, y_begin, y_end, clockwise); @@ -1896,9 +2016,9 @@ void rasterize_edge_textured_gouraud(double Vxy[][2], double Zvertex[2], double for (short int k = 0; k < sizeA; k++) { - image[sizeA * indx + k] *= T; - image[sizeA * indx + k] += (1 - T) * A[k] * L; + color[k] = A[k] * L; } + image.writePixelTransparent(x, y, color, T); } indx++; } @@ -2714,40 +2834,10 @@ void checkSceneValid(Scene scene, bool has_derivatives) } } -void renderScene(Scene scene, double *image, double *z_buffer, double sigma, bool antialiaseError = 0, double *obs = NULL, double *err_buffer = NULL) +void computeTrianglesAreasAndVerticesDepthSums(Scene &scene, vector &signedAreaV, vector &sum_depth) { - - checkSceneValid(scene, false); - // first pass : render triangle without edge antialiasing - - int Texture_size[2]; - - Texture_size[1] = scene.texture_height; - Texture_size[0] = scene.texture_width; - - if (scene.background_image != NULL) - { - memcpy(image, scene.background_image, scene.height * scene.width * scene.nb_colors * sizeof(double)); - } - else - { - for (int i = 0; i < scene.height * scene.width; i++) - { - for (int k = 0; k < scene.nb_colors; k++) - { - image[i * scene.nb_colors + k] = scene.background_color[k]; - } - } - } - //for (int k=0;k::infinity()); - - vector sum_depth; - sum_depth.resize(scene.nb_triangles); - vector signedAreaV; signedAreaV.resize(scene.nb_triangles); - + sum_depth.resize(scene.nb_triangles); for (int k = 0; k < scene.nb_triangles; k++) { sum_depth[k].value = 0; @@ -2777,6 +2867,106 @@ void renderScene(Scene scene, double *image, double *z_buffer, double sigma, boo signedAreaV[k] = 0; } } +} + +void renderSceneFragments( + Scene &scene, + double *z_buffer, double sigma, + Fragments &image) +{ + checkSceneValid(scene, false); + // first pass : render triangle without edge antialiasing + + int Texture_size[2]; + + Texture_size[1] = scene.texture_height; + Texture_size[0] = scene.texture_width; + + //for (int k=0;k::infinity()); + + vector sum_depth; + vector signedAreaV; + + computeTrianglesAreasAndVerticesDepthSums(scene, signedAreaV, sum_depth); + + sort(sum_depth.begin(), sum_depth.end(), sortcompare()); + + float pixel_center_offset = scene.integer_pixel_centers ? 0 : 0.5; + + for (int k = 0; k < scene.nb_triangles; k++) + if ((signedAreaV[k] > 0) || (!scene.backface_culling)) + { + unsigned int *face = &scene.faces[k * 3]; + double ij[3][2]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + ij[i][j] = scene.ij[face[i] * 2 + j] - pixel_center_offset; + + double depths[3]; + for (int i = 0; i < 3; i++) + depths[i] = scene.depths[face[i]]; + + if ((scene.textured[k] && scene.shaded[k])) + { + unsigned int *face_uv = &scene.faces_uv[k * 3]; + double shade[3]; + for (int i = 0; i < 3; i++) + shade[i] = scene.shade[face[i]]; + double uv[3][2]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + { + uv[i][j] = scene.uv[face_uv[i] * 2 + j]; + } + + rasterize_triangle_textured_gouraud(ij, depths, uv, shade, z_buffer, image, scene.height, scene.width, scene.nb_colors, scene.texture, Texture_size, scene.strict_edge, scene.perspective_correct); + } + if (!scene.textured[k]) + { + double *colors[3]; + for (int i = 0; i < 3; i++) + colors[i] = scene.colors + face[i] * scene.nb_colors; + rasterize_triangle_interpolated(ij, depths, colors, z_buffer, image, scene.height, scene.width, scene.nb_colors, scene.strict_edge, scene.perspective_correct); + } + } +} + +void renderScene(Scene &scene, double *image_data, double *z_buffer, double sigma, bool antialiaseError = 0, double *obs = NULL, double *err_buffer = NULL) +{ + Image image(scene.width, scene.height, scene.nb_colors, image_data); + + checkSceneValid(scene, false); + // first pass : render triangle without edge antialiasing + + int Texture_size[2]; + + Texture_size[1] = scene.texture_height; + Texture_size[0] = scene.texture_width; + + if (scene.background_image != NULL) + { + memcpy(image.data, scene.background_image, scene.height * scene.width * scene.nb_colors * sizeof(double)); + } + else + { + for (int i = 0; i < scene.height * scene.width; i++) + { + for (int k = 0; k < scene.nb_colors; k++) + { + image.data[i * scene.nb_colors + k] = scene.background_color[k]; + } + } + } + //for (int k=0;k::infinity()); + + vector sum_depth; + vector signedAreaV; + + computeTrianglesAreasAndVerticesDepthSums(scene, signedAreaV, sum_depth); sort(sum_depth.begin(), sum_depth.end(), sortcompare()); @@ -2829,7 +3019,7 @@ void renderScene(Scene scene, double *image, double *z_buffer, double sigma, boo double d; for (int i = 0; i < scene.nb_colors; i++) { - d = (image[scene.nb_colors * k + i] - obs[scene.nb_colors * k + i]); + d = (image.data[scene.nb_colors * k + i] - obs[scene.nb_colors * k + i]); s += d * d; } err_buffer[k] = s; @@ -2900,7 +3090,7 @@ void renderScene(Scene scene, double *image, double *z_buffer, double sigma, boo } } -void renderScene_B(Scene scene, double *image, double *z_buffer, double *image_b, double sigma, bool antialiaseError = 0, double *obs = NULL, double *err_buffer = NULL, double *err_buffer_b = NULL) +void renderScene_B(Scene &scene, double *image, double *z_buffer, double *image_b, double sigma, bool antialiaseError = 0, double *obs = NULL, double *err_buffer = NULL, double *err_buffer_b = NULL) { // first pass : render triangle without edge antialiasing @@ -2914,45 +3104,15 @@ void renderScene_B(Scene scene, double *image, double *z_buffer, double *image_b int list_sub[3][2] = {1, 0, 2, 1, 0, 2}; - vector sum_depth; - sum_depth.resize(scene.nb_triangles); - vector signedAreaV; - signedAreaV.resize(scene.nb_triangles); - if (!scene.backface_culling) { - throw "You have to use backface_culling true if you ant to compute gradients"; + throw "You have to use backface_culling true if you want to compute gradients"; } - for (int k = 0; k < scene.nb_triangles; k++) - { - sum_depth[k].value = 0; - sum_depth[k].index = k; - - bool all_verticesInFront = true; - unsigned int *face = &scene.faces[k * 3]; + vector sum_depth; + vector signedAreaV; - for (int i = 0; i < 3; i++) - { - if (scene.depths[face[i]] < 0) - { - all_verticesInFront = false; - } - sum_depth[k].value += scene.depths[face[i]]; - } - if (all_verticesInFront) - { - double ij[3][2]; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 2; j++) - ij[i][j] = scene.ij[face[i] * 2 + j]; - signedAreaV[k] = signedArea(ij, scene.clockwise); - } - else - { - signedAreaV[k] = 0; - } - } + computeTrianglesAreasAndVerticesDepthSums(scene, signedAreaV, sum_depth); sort(sum_depth.begin(), sum_depth.end(), sortcompare()); diff --git a/deodr/_differentiable_renderer.pxd b/deodr/_differentiable_renderer.pxd index c5ecd0d..311cbde 100644 --- a/deodr/_differentiable_renderer.pxd +++ b/deodr/_differentiable_renderer.pxd @@ -1,5 +1,6 @@ # distutils: language=c++ from libcpp cimport bool +from libcpp.vector cimport vector cdef extern from "../C++/DifferentiableRenderer.h": ctypedef struct Scene: unsigned int* faces; @@ -33,5 +34,16 @@ cdef extern from "../C++/DifferentiableRenderer.h": bool strict_edge bool perspective_correct bool integer_pixel_centers + + ctypedef struct FragmentsDouble: + vector[int] list_x + vector[int] list_y + vector[double] list_values + vector[double] list_alpha + int nb_channels + int width + int height + void renderScene(Scene scene,double* image,double* z_buffer,double sigma,bool antialiase_error ,double* obs,double* err_buffer) void renderScene_B(Scene scene,double* image,double* z_buffer,double* image_b,double sigma,bool antialiase_error ,double* obs,double* err_buffer, double* err_buffer_b) + void renderSceneFragments(Scene scene,double* z_buffer, double sigma, FragmentsDouble fragments) \ No newline at end of file diff --git a/deodr/differentiable_renderer.py b/deodr/differentiable_renderer.py index b89b494..5a19429 100644 --- a/deodr/differentiable_renderer.py +++ b/deodr/differentiable_renderer.py @@ -47,6 +47,88 @@ class Scene2DBase: integer_pixel_centers: bool = True +def _check_scene_2d(scene: Scene2DBase, check_b: bool = False) -> None: + + nb_colors = scene.nb_colors + nb_triangles = scene.faces.shape[0] + assert nb_triangles == scene.faces_uv.shape[0] + nb_vertices = scene.depths.shape[0] + nb_vertices_uv = scene.uv.shape[0] + + assert scene.faces.dtype == np.uint32 + assert np.all(scene.faces < nb_vertices) + assert np.all(scene.faces_uv < nb_vertices_uv) + + assert scene.colors.ndim == 2 + assert scene.uv.ndim == 2 + assert scene.ij.ndim == 2 + assert scene.shade.ndim == 1 + assert scene.edgeflags.ndim == 2 + assert scene.textured.ndim == 1 + assert scene.shaded.ndim == 1 + assert scene.uv.shape[1] == 2 + assert scene.ij.shape[0] == nb_vertices + assert scene.ij.shape[1] == 2 + assert scene.shade.shape[0] == nb_vertices + assert scene.colors.shape[0] == nb_vertices + assert scene.colors.shape[1] == nb_colors + assert scene.edgeflags.shape[0] == nb_triangles + assert scene.edgeflags.shape[1] == 3 + assert scene.textured.shape[0] == nb_triangles + assert scene.shaded.shape[0] == nb_triangles + + assert (scene.background_image is not None) != (scene.background_color is not None) + + if scene.background_image is not None: + assert scene.background_image.ndim == 3 + # assert scene.background_image.shape[0] == height + # assert scene.background_image.shape[1] == width + assert scene.background_image.shape[2] == nb_colors + assert ( + scene.background_color is None + ), "You need to provide either background_image or background_color" + else: + assert ( + scene.background_color is not None + ), "You need to provide background_image or background_color" + assert scene.background_color.shape[0] == nb_colors + + if scene.texture.size > 0: + assert scene.texture.ndim == 3 + assert scene.texture.shape[0] > 0 + assert scene.texture.shape[1] > 0 + assert scene.texture.shape[2] == nb_colors + + if check_b: + assert scene.uv_b is not None + assert scene.ij_b is not None + assert scene.shade_b is not None + assert scene.uv_b is not None + assert scene.colors_b is not None + + assert scene.uv_b.ndim == 2 + assert scene.ij_b.ndim == 2 + assert scene.shade_b.ndim == 1 + + assert scene.uv_b.shape[0] == nb_vertices_uv + assert scene.uv_b.shape[1] == 2 + assert scene.ij_b.shape[0] == nb_vertices + assert scene.ij_b.shape[1] == 2 + assert scene.shade_b.shape[0] == nb_vertices + assert scene.colors_b.shape[0] == nb_vertices + assert scene.colors_b.shape[1] == nb_colors + + if scene.texture.size > 0: + assert scene.texture_b is not None + assert scene.texture_b.ndim == 3 + assert scene.texture.shape[0] > 0 + assert scene.texture.shape[1] > 0 + assert scene.texture.shape[0] == scene.texture_b.shape[0] + assert scene.texture.shape[1] == scene.texture_b.shape[1] + assert scene.texture.shape[2] == nb_colors + assert scene.texture_b.shape[2] == nb_colors + + def renderScene( scene: Scene2DBase, sigma: float, @@ -62,63 +144,18 @@ def renderScene( # doing checks here as it seems the debugger in not able to find the pyx file # when installed from a wheel. this also make interactive debugging easier # for the library user - + _check_scene_2d(scene, check_b=False) assert image is not None assert z_buffer is not None height = image.shape[0] width = image.shape[1] nb_colors = image.shape[2] - nb_triangles = scene.faces.shape[0] - assert nb_triangles == scene.faces_uv.shape[0] - nb_vertices = scene.depths.shape[0] - nb_vertices_uv = scene.uv.shape[0] - - assert scene.faces.dtype == np.uint32 - assert np.all(scene.faces < nb_vertices) - assert np.all(scene.faces_uv < nb_vertices_uv) - - assert scene.colors.ndim == 2 - assert scene.uv.ndim == 2 - assert scene.ij.ndim == 2 - assert scene.shade.ndim == 1 - assert scene.edgeflags.ndim == 2 - assert scene.textured.ndim == 1 - assert scene.shaded.ndim == 1 - assert scene.uv.shape[1] == 2 - assert scene.ij.shape[0] == nb_vertices - assert scene.ij.shape[1] == 2 - assert scene.shade.shape[0] == nb_vertices - assert scene.colors.shape[0] == nb_vertices - assert scene.colors.shape[1] == nb_colors - assert scene.edgeflags.shape[0] == nb_triangles - assert scene.edgeflags.shape[1] == 3 - assert scene.textured.shape[0] == nb_triangles - assert scene.shaded.shape[0] == nb_triangles - - assert (scene.background_image is not None) != ( - scene.background_color is not None - ) + assert scene.nb_colors == nb_colors if scene.background_image is not None: - assert scene.background_image.ndim == 3 assert scene.background_image.shape[0] == height assert scene.background_image.shape[1] == width - assert scene.background_image.shape[2] == nb_colors - assert ( - scene.background_color is None - ), "You need to provide either background_image or background_color" - else: - assert ( - scene.background_color is not None - ), "You need to provide background_image or background_color" - assert scene.background_color.shape[0] == nb_colors - - if scene.texture.size > 0: - assert scene.texture.ndim == 3 - assert scene.texture.shape[0] > 0 - assert scene.texture.shape[1] > 0 - assert scene.texture.shape[2] == nb_colors assert z_buffer.shape[0] == height assert z_buffer.shape[1] == width @@ -137,6 +174,21 @@ def renderScene( ) +def renderSceneFragments( + scene: Scene2DBase, + sigma: float, + z_buffer: np.ndarray, + check_valid: bool = True, +) -> Any: + if check_valid: + _check_scene_2d(scene) + + fragments = differentiable_renderer_cython.renderSceneFragments( + scene, sigma, z_buffer + ) + return fragments + + def renderSceneB( scene: Scene2DBase, sigma: float, @@ -154,105 +206,29 @@ def renderSceneB( # doing checks here as it seems the debugger in not able to find the pyx file # when installed from a wheel. this also make interactive debugging easier # for the library user - + _check_scene_2d(scene, check_b=True) assert image is not None assert z_buffer is not None height = image.shape[0] width = image.shape[1] nb_colors = image.shape[2] - nb_triangles = scene.faces.shape[0] assert nb_colors == scene.colors.shape[1] assert z_buffer.shape[0] == height assert z_buffer.shape[1] == width - assert nb_triangles == scene.faces_uv.shape[0] - - nb_vertices = scene.depths.shape[0] - nb_vertices_uv = scene.uv.shape[0] - - assert scene.faces.dtype == np.uint32 - assert np.all(scene.faces < nb_vertices) - assert np.all(scene.faces_uv < nb_vertices_uv) - - assert scene.colors.ndim == 2 - assert scene.uv.ndim == 2 - assert scene.ij.ndim == 2 - assert scene.shade.ndim == 1 - assert scene.edgeflags.ndim == 2 - assert scene.textured.ndim == 1 - assert scene.shaded.ndim == 1 - assert scene.uv.shape[1] == 2 - assert scene.ij.shape[0] == nb_vertices - assert scene.ij.shape[1] == 2 - assert scene.shade.shape[0] == nb_vertices - assert scene.colors.shape[0] == nb_vertices - assert scene.colors.shape[1] == nb_colors - assert scene.edgeflags.shape[0] == nb_triangles - assert scene.edgeflags.shape[1] == 3 - assert scene.textured.shape[0] == nb_triangles - assert scene.shaded.shape[0] == nb_triangles - - assert (scene.background_image is not None) != ( - scene.background_color is not None - ) - - if scene.background_image is not None: - assert scene.background_image.ndim == 3 - assert scene.background_image.shape[0] == height - assert scene.background_image.shape[1] == width - assert scene.background_image.shape[2] == nb_colors - assert ( - scene.background_color is None - ), "You need to provide either background_image or background_color" - else: - assert ( - scene.background_color is not None - ), "You need to provide background_image or background_color" - assert scene.background_color.shape[0] == nb_colors - - assert scene.uv_b is not None - assert scene.ij_b is not None - assert scene.shade_b is not None - assert scene.uv_b is not None - assert scene.colors_b is not None - - assert scene.uv_b.ndim == 2 - assert scene.ij_b.ndim == 2 - assert scene.shade_b.ndim == 1 - assert scene.edgeflags.ndim == 2 - assert scene.textured.ndim == 1 - assert scene.shaded.ndim == 1 - assert scene.uv_b.shape[0] == nb_vertices_uv - assert scene.uv_b.shape[1] == 2 - assert scene.ij_b.shape[0] == nb_vertices - assert scene.ij_b.shape[1] == 2 - assert scene.shade_b.shape[0] == nb_vertices - assert scene.colors_b.shape[0] == nb_vertices - assert scene.colors_b.shape[1] == nb_colors - - if scene.texture.size > 0: - assert scene.texture_b is not None - assert scene.texture.ndim == 3 - assert scene.texture_b.ndim == 3 - assert scene.texture.shape[0] > 0 - assert scene.texture.shape[1] > 0 - assert scene.texture.shape[0] == scene.texture_b.shape[0] - assert scene.texture.shape[1] == scene.texture_b.shape[1] - assert scene.texture.shape[2] == nb_colors - assert scene.texture_b.shape[2] == nb_colors - if antialiase_error: - assert err_buffer is not None - assert obs is not None - assert err_buffer.shape[0] == height - assert err_buffer.shape[1] == width - assert obs.shape[0] == height - assert obs.shape[1] == width - else: - assert image_b is not None - assert image_b.shape[0] == height - assert image_b.shape[1] == width + if antialiase_error: + assert err_buffer is not None + assert obs is not None + assert err_buffer.shape[0] == height + assert err_buffer.shape[1] == width + assert obs.shape[0] == height + assert obs.shape[1] == width + else: + assert image_b is not None + assert image_b.shape[0] == height + assert image_b.shape[1] == width differentiable_renderer_cython.renderSceneB( scene, @@ -669,6 +645,11 @@ def render(self, sigma: float = 1) -> Tuple[np.ndarray, np.ndarray]: self.store_backward = (sigma, image, z_buffer) return image, z_buffer + def render_fragments(self, sigma: float = 1) -> Any: + z_buffer = np.zeros((self.height, self.width)) + fragments = renderSceneFragments(self, sigma, z_buffer) + return fragments + def render_error_backward( self, err_buffer_b: np.ndarray, make_copies: bool = True ) -> None: @@ -977,6 +958,39 @@ def render( return_z_buffer: bool = False, backface_culling: bool = True, ) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]: + self._generate_scene_2d( + camera=camera, + return_z_buffer=return_z_buffer, + backface_culling=backface_culling, + ) + image, z_buffer = self._render_2d() + if self.store_backward_current is not None: + self.store_backward_current["render"] = ( + camera, + ) # store this field as it could be overwritten when + # rendering several views + return (image, z_buffer) if return_z_buffer else image + + def render_fragments( + self, + camera: Camera, + return_z_buffer: bool = False, + backface_culling: bool = True, + ) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]: + self._generate_scene_2d( + camera=camera, + return_z_buffer=return_z_buffer, + backface_culling=backface_culling, + ) + fragments = self.scene_2d.render_fragments() + return fragments + + def _generate_scene_2d( + self, + camera: Camera, + return_z_buffer: bool = False, + backface_culling: bool = True, + ) -> None: assert self.mesh is not None, "You need to provide a mesh first." self.store_backward_current = {} @@ -1059,15 +1073,6 @@ def render( ) self.scene_2d = scene_2d - image, z_buffer = self._render_2d() - if self.store_backward_current is not None: - self.store_backward_current["render"] = ( - camera, - edgeflags, - ) # store this field as it could be overwritten when - # rendering several views - return (image, z_buffer) if return_z_buffer else image - def render_backward(self, image_b: np.ndarray) -> None: assert self.scene_2d is not None assert self.scene_2d.colors_b is not None @@ -1077,7 +1082,7 @@ def render_backward(self, image_b: np.ndarray) -> None: "perspective_correct not supported yet for gradient back propagation" ) assert self.store_backward_current is not None - camera, self.edgeflags = self.store_backward_current["render"] + (camera,) = self.store_backward_current["render"] self._render_2d_backward(image_b) self._compute_vertices_colors_with_illumination_backward(self.scene_2d.colors_b) self.mesh._vertices_b = camera.project_points_backward( diff --git a/deodr/differentiable_renderer_cython.pyx b/deodr/differentiable_renderer_cython.pyx index da5728d..bcecd19 100644 --- a/deodr/differentiable_renderer_cython.pyx +++ b/deodr/differentiable_renderer_cython.pyx @@ -1,26 +1,27 @@ # distutils: language = c++ from libcpp cimport bool -cimport _differentiable_renderer +from libcpp.vector cimport vector +cimport _differentiable_renderer import cython # import both numpy and the Cython declarations for numpy import numpy as np cimport numpy as np - +from cpython cimport Py_buffer @cython.boundscheck(False) @cython.wraparound(False) -def renderScene(scene, +def renderScene(scene, double sigma, - np.ndarray[double,ndim = 3,mode = "c"] image, + np.ndarray[double,ndim = 3,mode = "c"] image, np.ndarray[double,ndim = 2,mode = "c"] z_buffer, bool antialiase_error = 0, np.ndarray[double,ndim = 3,mode = "c"] obs = None, - np.ndarray[double,ndim = 2,mode = "c"] err_buffer = None, + np.ndarray[double,ndim = 2,mode = "c"] err_buffer = None, bool check_valid = 1): - - cdef _differentiable_renderer.Scene scene_c + + cdef _differentiable_renderer.Scene scene_c if check_valid: assert (not(image is None)) @@ -29,25 +30,25 @@ def renderScene(scene, height = image.shape[0] width = image.shape[1] nb_colors = image.shape[2] - + nb_triangles = scene.faces.shape[0] assert(nb_triangles == scene.faces_uv.shape[0]) nb_vertices = scene.depths.shape[0] nb_vertices_uv = scene.uv.shape[0] - if check_valid: + if check_valid: assert(scene.faces.dtype == np.uint32) assert(np.all(scene.faces < nb_vertices)) assert(np.all(scene.faces_uv < nb_vertices_uv)) - + assert(scene.colors.ndim == 2) assert(scene.uv.ndim == 2) assert(scene.ij.ndim == 2) assert(scene.shade.ndim == 1) assert(scene.edgeflags.ndim == 2) assert(scene.textured.ndim == 1) - assert(scene.shaded.ndim == 1) - assert(scene.uv.shape[1] == 2) + assert(scene.shaded.ndim == 1) + assert(scene.uv.shape[1] == 2) assert(scene.ij.shape[0] == nb_vertices) assert(scene.ij.shape[1] == 2) assert(scene.shade.shape[0] == nb_vertices) @@ -57,7 +58,7 @@ def renderScene(scene, assert(scene.edgeflags.shape[1] == 3) assert(scene.textured.shape[0] == nb_triangles) assert(scene.shaded.shape[0] == nb_triangles) - + assert ((scene.background_image is not None) != (scene.background_color is not None)) if scene.background_image is not None: @@ -67,20 +68,20 @@ def renderScene(scene, assert scene.background_image.shape[2] == nb_colors else: assert scene.background_color.shape[0] == nb_colors - + if scene.texture.size>0: assert(scene.texture.ndim == 3) assert(scene.texture.shape[0]>0) assert(scene.texture.shape[1]>0) assert(scene.texture.shape[2] == nb_colors) - - assert z_buffer.shape[0] == height - assert z_buffer.shape[1] == width + + assert z_buffer.shape[0] == height + assert z_buffer.shape[1] == width scene_c.nb_colors = nb_colors cdef np.ndarray[np.uint32_t, mode = "c"] faces_c = np.ascontiguousarray(scene.faces.flatten(), dtype = np.uint32) - cdef np.ndarray[np.uint32_t, mode = "c"] faces_uv_c = np.ascontiguousarray(scene.faces_uv.flatten(), dtype = np.uint32) - cdef np.ndarray[np.double_t, mode = "c"] depths_c = np.ascontiguousarray(scene.depths.flatten(), dtype = np.double) + cdef np.ndarray[np.uint32_t, mode = "c"] faces_uv_c = np.ascontiguousarray(scene.faces_uv.flatten(), dtype = np.uint32) + cdef np.ndarray[np.double_t, mode = "c"] depths_c = np.ascontiguousarray(scene.depths.flatten(), dtype = np.double) cdef np.ndarray[np.double_t, mode = "c"] uv_c = np.ascontiguousarray(scene.uv.flatten(), dtype = np.double) cdef np.ndarray[np.double_t, mode = "c"] ij_c = np.ascontiguousarray(scene.ij.flatten(), dtype = np.double) cdef np.ndarray[np.double_t, mode = "c"] shade_c = np.ascontiguousarray(scene.shade.flatten(), dtype = np.double) @@ -98,7 +99,7 @@ def renderScene(scene, background_color_c = np.ascontiguousarray(scene.background_color.flatten(), dtype = np.double) scene_c.height = scene.height - scene_c.width = scene.width + scene_c.width = scene.width scene_c.nb_triangles = nb_triangles scene_c.nb_vertices = nb_vertices scene_c.backface_culling = scene.backface_culling @@ -115,8 +116,8 @@ def renderScene(scene, scene_c.textured = textured_c.data scene_c.shaded = shaded_c.data scene_c.texture = texture_c.data - - if scene.background_image is not None: + + if scene.background_image is not None: scene_c.background_image = background_image_c.data scene_c.background_color = NULL if scene_c.background_image == NULL: @@ -137,39 +138,270 @@ def renderScene(scene, cdef double* obs_ptr = NULL cdef double* err_buffer_ptr = NULL - + cdef double* image_ptr = image.data cdef double* z_buffer_ptr = z_buffer.data - + if image_ptr == NULL: raise BaseException('image_ptr is NULL') if z_buffer_ptr == NULL: raise BaseException('z_buffer_ptr is NULL') - + if antialiase_error: - assert err_buffer.shape[0] == height + assert err_buffer.shape[0] == height assert err_buffer.shape[1] == width - assert obs.shape[0] == height + assert obs.shape[0] == height assert obs.shape[1] == width - assert obs.shape[2] == nb_colors - + assert obs.shape[2] == nb_colors + obs_ptr = obs.data err_buffer_ptr = err_buffer.data - + if err_buffer_ptr == NULL: raise BaseException('err_buffer_ptr is NULL') if obs_ptr == NULL: raise BaseException('obs_ptr is NULL') - + _differentiable_renderer.renderScene( scene_c,image_ptr, z_buffer_ptr, sigma, antialiase_error ,obs_ptr, err_buffer_ptr) - + + + + +cdef class VecInt: + + cdef Py_ssize_t shape[1] + cdef Py_ssize_t strides[1] + cdef vector[int] v + + def __cinit__(self): + pass + + def set_data(self, vector[int]& data): + self.v.swap(data) + + + def __getbuffer__(self, Py_buffer *buffer, int flags): + cdef Py_ssize_t itemsize = sizeof(self.v[0]) + + self.shape[0] = self.v.size() + self.strides[0] = sizeof(int) + + buffer.buf = &(self.v[0]) + buffer.format = 'i' # int + buffer.internal = NULL # see References + buffer.itemsize = itemsize + buffer.len = self.v.size() * itemsize # product(shape) * itemsize + buffer.ndim = 1 + buffer.obj = self + buffer.readonly = 0 + buffer.shape = self.shape + buffer.strides = self.strides + buffer.suboffsets = NULL # for pointer arrays only + + def __releasebuffer__(self, Py_buffer *buffer): + pass + +cdef class VecFloat: + + cdef Py_ssize_t shape[1] + cdef Py_ssize_t strides[1] + cdef vector[float] v + + def __cinit__(self): + pass + + def set_data(self, vector[float]& data): + self.v.swap(data) + + + def __getbuffer__(self, Py_buffer *buffer, int flags): + cdef Py_ssize_t itemsize = sizeof(self.v[0]) + + self.shape[0] = self.v.size() + self.strides[0] = sizeof(int) + + buffer.buf = &(self.v[0]) + buffer.format = 'f' # float + buffer.internal = NULL # see References + buffer.itemsize = itemsize + buffer.len = self.v.size() * itemsize # product(shape) * itemsize + buffer.ndim = 1 + buffer.obj = self + buffer.readonly = 0 + buffer.shape = self.shape + buffer.strides = self.strides + buffer.suboffsets = NULL # for pointer arrays only + + def __releasebuffer__(self, Py_buffer *buffer): + pass + @cython.boundscheck(False) -@cython.wraparound(False) -def renderSceneB(scene, +@cython.wraparound(False) +def renderSceneFragments(scene, double sigma, - np.ndarray[double,ndim = 3,mode = "c"] image, + np.ndarray[double,ndim = 2,mode = "c"] z_buffer, + bool antialiase_error = 0, + bool check_valid = 1 +): + + cdef _differentiable_renderer.Scene scene_c + cdef _differentiable_renderer.FragmentsDouble fragments + + if check_valid: + assert (not(z_buffer is None)) + + + nb_triangles = scene.faces.shape[0] + assert(nb_triangles == scene.faces_uv.shape[0]) + nb_vertices = scene.depths.shape[0] + nb_vertices_uv = scene.uv.shape[0] + + if check_valid: + assert(scene.faces.dtype == np.uint32) + assert(np.all(scene.faces < nb_vertices)) + assert(np.all(scene.faces_uv < nb_vertices_uv)) + + assert(scene.colors.ndim == 2) + assert(scene.uv.ndim == 2) + assert(scene.ij.ndim == 2) + assert(scene.shade.ndim == 1) + assert(scene.edgeflags.ndim == 2) + assert(scene.textured.ndim == 1) + assert(scene.shaded.ndim == 1) + assert(scene.uv.shape[1] == 2) + assert(scene.ij.shape[0] == nb_vertices) + assert(scene.ij.shape[1] == 2) + assert(scene.shade.shape[0] == nb_vertices) + assert(scene.colors.shape[0] == nb_vertices) + nb_colors= scene.colors.shape[1] + + assert(scene.edgeflags.shape[0] == nb_triangles) + assert(scene.edgeflags.shape[1] == 3) + assert(scene.textured.shape[0] == nb_triangles) + assert(scene.shaded.shape[0] == nb_triangles) + + assert ((scene.background_image is not None) != (scene.background_color is not None)) + + if scene.background_image is not None: + assert scene.background_image.ndim == 3 + assert scene.background_image.shape[2] == nb_colors + else: + assert scene.background_color.shape[0] == nb_colors + + if scene.texture.size>0: + assert(scene.texture.ndim == 3) + assert(scene.texture.shape[0]>0) + assert(scene.texture.shape[1]>0) + assert(scene.texture.shape[2] == nb_colors) + + assert z_buffer.shape[0] == scene.height + assert z_buffer.shape[1] == scene.width + + + scene_c.nb_colors = nb_colors + cdef np.ndarray[np.uint32_t, mode = "c"] faces_c = np.ascontiguousarray(scene.faces.flatten(), dtype = np.uint32) + cdef np.ndarray[np.uint32_t, mode = "c"] faces_uv_c = np.ascontiguousarray(scene.faces_uv.flatten(), dtype = np.uint32) + cdef np.ndarray[np.double_t, mode = "c"] depths_c = np.ascontiguousarray(scene.depths.flatten(), dtype = np.double) + cdef np.ndarray[np.double_t, mode = "c"] uv_c = np.ascontiguousarray(scene.uv.flatten(), dtype = np.double) + cdef np.ndarray[np.double_t, mode = "c"] ij_c = np.ascontiguousarray(scene.ij.flatten(), dtype = np.double) + cdef np.ndarray[np.double_t, mode = "c"] shade_c = np.ascontiguousarray(scene.shade.flatten(), dtype = np.double) + cdef np.ndarray[np.double_t, mode = "c"] colors_c = np.ascontiguousarray(scene.colors.flatten(), dtype = np.double) + cdef np.ndarray[np.uint8_t, mode = "c"] edgeflags_c = np.ascontiguousarray(scene.edgeflags.flatten(), dtype = np.uint8) + cdef np.ndarray[np.uint8_t, mode = "c"] textured_c = np.ascontiguousarray(scene.textured.flatten(), dtype = np.uint8) + cdef np.ndarray[np.uint8_t, mode = "c"] shaded_c = np.ascontiguousarray(scene.shaded.flatten(), dtype = np.uint8) + cdef np.ndarray[np.double_t, mode = "c"] texture_c = np.ascontiguousarray(scene.texture.flatten(), dtype = np.double) + cdef np.ndarray[np.double_t, mode = "c"] background_image_c; + cdef np.ndarray[np.double_t, mode = "c"] background_color_c; + + if scene.background_image is not None: + background_image_c = np.ascontiguousarray(scene.background_image.flatten(), dtype = np.double) + else: + background_color_c = np.ascontiguousarray(scene.background_color.flatten(), dtype = np.double) + + scene_c.height = scene.height + scene_c.width = scene.width + scene_c.nb_triangles = nb_triangles + scene_c.nb_vertices = nb_vertices + scene_c.backface_culling = scene.backface_culling + scene_c.clockwise = scene.clockwise + scene_c.nb_uv = nb_vertices_uv + scene_c.faces = faces_c.data + scene_c.faces_uv = faces_uv_c.data + scene_c.depths = depths_c.data + scene_c.uv = uv_c.data + scene_c.ij = ij_c.data + scene_c.shade = shade_c.data + scene_c.colors = colors_c.data + scene_c.edgeflags = edgeflags_c.data + scene_c.textured = textured_c.data + scene_c.shaded = shaded_c.data + scene_c.texture = texture_c.data + + if scene.background_image is not None: + scene_c.background_image = background_image_c.data + scene_c.background_color = NULL + if scene_c.background_image == NULL: + raise BaseException('scene_c.background_image_c is NULL') + + else: + scene_c.background_image = NULL + scene_c.background_color = background_color_c.data + if scene_c.background_color == NULL: + raise BaseException('scene_c.background_color is NULL') + + scene_c.texture_height = scene.texture.shape[0] + scene_c.texture_width = scene.texture.shape[1] + scene_c.strict_edge = scene.strict_edge + scene_c.perspective_correct = scene.perspective_correct + scene_c.integer_pixel_centers = scene.integer_pixel_centers + + + cdef double* obs_ptr = NULL + cdef double* err_buffer_ptr = NULL + + cdef double* z_buffer_ptr = z_buffer.data + + if z_buffer_ptr == NULL: + raise BaseException('z_buffer_ptr is NULL') + + + fragments.width=scene.width + fragments.height=scene.height + fragments.nb_channels=nb_colors + + _differentiable_renderer.renderSceneFragments( + scene_c, + z_buffer_ptr, + sigma, + fragments + ) + + + list_x= VecInt() + list_x.set_data(fragments.list_x) + + list_y =VecInt() + list_y.set_data(fragments.list_y) + + list_alpha =VecFloat() + list_alpha.set_data(fragments.list_alpha) + + list_values =VecFloat() + list_values.set_data(fragments.list_values) + x= np.asarray(list_x) + y= np.asarray(list_y) + alpha = np.asarray(list_alpha) + values = np.array(list_values).reshape(-1,nb_colors) + return x, y, alpha, values + + +@cython.boundscheck(False) +@cython.wraparound(False) +def renderSceneB(scene, + double sigma, + np.ndarray[double,ndim = 3,mode = "c"] image, np.ndarray[double,ndim = 2,mode = "c"] z_buffer, np.ndarray[double,ndim = 3,mode = "c"] image_b = None, bool antialiase_error = 0, @@ -178,39 +410,39 @@ def renderSceneB(scene, np.ndarray[double,ndim = 2,mode = "c"] err_buffer_b = None, bool check_valid=1): - cdef _differentiable_renderer.Scene scene_c + cdef _differentiable_renderer.Scene scene_c if check_valid: assert (not(image is None)) assert (not(z_buffer is None)) - + height = image.shape[0] width = image.shape[1] nb_colors = image.shape[2] nb_triangles = scene.faces.shape[0] - + if check_valid: - assert(nb_colors == scene.colors.shape[1]) - assert z_buffer.shape[0] == height - assert z_buffer.shape[1] == width + assert(nb_colors == scene.colors.shape[1]) + assert z_buffer.shape[0] == height + assert z_buffer.shape[1] == width assert(nb_triangles == scene.faces_uv.shape[0]) nb_vertices = scene.depths.shape[0] nb_vertices_uv = scene.uv.shape[0] - + if check_valid: assert(scene.faces.dtype == np.uint32) assert(np.all(scene.faces0: assert(scene.texture.ndim == 3) - assert(scene.texture_b.ndim == 3) + assert(scene.texture_b.ndim == 3) assert(scene.texture.shape[0]>0) - assert(scene.texture.shape[1]>0) + assert(scene.texture.shape[1]>0) assert(scene.texture.shape[0] == scene.texture_b.shape[0]) assert(scene.texture.shape[1] == scene.texture_b.shape[1]) - assert(scene.texture.shape[2] == nb_colors) + assert(scene.texture.shape[2] == nb_colors) assert(scene.texture_b.shape[2] == nb_colors) - + scene_c.nb_colors = nb_colors - + cdef np.ndarray[np.uint32_t, mode = "c"] faces_c = np.ascontiguousarray(scene.faces.flatten(), dtype = np.uint32) cdef np.ndarray[np.uint32_t, mode = "c"] faces_uv_c = np.ascontiguousarray(scene.faces_uv.flatten(), dtype = np.uint32) - cdef np.ndarray[np.double_t, mode = "c"] depths_c = np.ascontiguousarray(scene.depths.flatten(), dtype = np.double) + cdef np.ndarray[np.double_t, mode = "c"] depths_c = np.ascontiguousarray(scene.depths.flatten(), dtype = np.double) cdef np.ndarray[np.double_t, mode = "c"] uv_c = np.ascontiguousarray(scene.uv.flatten(), dtype = np.double) cdef np.ndarray[np.double_t, mode = "c"] ij_c = np.ascontiguousarray(scene.ij.flatten(), dtype = np.double) cdef np.ndarray[np.double_t, mode = "c"] uv_b_c = np.ascontiguousarray(scene.uv_b.flatten(), dtype = np.double) @@ -289,10 +521,10 @@ def renderSceneB(scene, scene_c.nb_triangles = nb_triangles scene_c.nb_vertices = nb_vertices scene_c.backface_culling = scene.backface_culling - scene_c.clockwise = scene.clockwise + scene_c.clockwise = scene.clockwise scene_c.nb_uv = nb_vertices_uv scene_c.faces = faces_c.data - scene_c.faces_uv = faces_uv_c.data + scene_c.faces_uv = faces_uv_c.data scene_c.depths = depths_c.data scene_c.uv = uv_c.data scene_c.uv_b = uv_b_c.data @@ -308,7 +540,7 @@ def renderSceneB(scene, scene_c.texture = texture_c.data scene_c.texture_b = texture_b_c.data - if scene.background_image is not None: + if scene.background_image is not None: scene_c.background_image = background_image_c.data scene_c.background_color = NULL if scene_c.background_image == NULL: @@ -325,32 +557,32 @@ def renderSceneB(scene, scene_c.strict_edge = scene.strict_edge scene_c.perspective_correct = scene.perspective_correct scene_c.integer_pixel_centers = scene.integer_pixel_centers - + cdef double* obs_ptr = NULL cdef double* err_buffer_ptr = NULL - cdef double* err_buffer_b_ptr = NULL + cdef double* err_buffer_b_ptr = NULL cdef double* image_ptr = image.data - + cdef double* image_b_ptr = NULL cdef double* z_buffer_ptr = z_buffer.data - + if image_ptr == NULL: - raise BaseException('image_ptr is NULL') + raise BaseException('image_ptr is NULL') if z_buffer_ptr == NULL: raise BaseException('z_buffer_ptr is NULL') - + if antialiase_error: if check_valid: - assert err_buffer.shape[0] == height - assert err_buffer.shape[1] == width - assert obs.shape[0] == height - assert obs.shape[1] == width - + assert err_buffer.shape[0] == height + assert err_buffer.shape[1] == width + assert obs.shape[0] == height + assert obs.shape[1] == width + err_buffer_ptr = err_buffer.data err_buffer_b_ptr = err_buffer_b.data obs_ptr = obs.data - + if err_buffer_ptr == NULL: raise BaseException('err_buffer_ptr is NULL') if err_buffer_b_ptr == NULL: @@ -360,16 +592,16 @@ def renderSceneB(scene, else: if check_valid: assert (not(image_b is None)) - assert image_b.shape[0] == height - assert image_b.shape[1] == width + assert image_b.shape[0] == height + assert image_b.shape[1] == width image_b_ptr = image_b.data if image_b_ptr == NULL: raise BaseException('image_b_ptr is NULL') - + _differentiable_renderer.renderScene_B( scene_c, image_ptr, z_buffer_ptr, image_b_ptr, sigma, antialiase_error ,obs_ptr, err_buffer_ptr, err_buffer_b_ptr) scene.uv_b = uv_b_c.reshape(scene.uv_b.shape) scene.ij_b = ij_b_c.reshape(scene.ij_b.shape) scene.shade_b = shade_b_c.reshape(scene.shade_b.shape) scene.colors_b = colors_b_c.reshape(scene.colors_b.shape) scene.texture_b = texture_b_c.reshape(scene.texture_b.shape) - + diff --git a/tests/test_depth_image_hand_fitting.py b/tests/test_depth_image_hand_fitting.py index 0c9d50d..efa104b 100644 --- a/tests/test_depth_image_hand_fitting.py +++ b/tests/test_depth_image_hand_fitting.py @@ -70,7 +70,6 @@ def test_depth_image_hand_fitting_tensorflow() -> None: if __name__ == "__main__": - test_depth_image_hand_fitting_pytorch() test_depth_image_hand_fitting_numpy() - + test_depth_image_hand_fitting_pytorch() test_depth_image_hand_fitting_tensorflow() diff --git a/tests/test_render_fragments.py b/tests/test_render_fragments.py new file mode 100644 index 0000000..a08a6ca --- /dev/null +++ b/tests/test_render_fragments.py @@ -0,0 +1,26 @@ +"""Test using rgb mesh rendering.""" + +import os + +import deodr +from deodr.examples.render_mesh import ( + example_moderngl, + example_channels, + example_rgb, + default_scene, +) +import imageio +import matplotlib.pyplot as plt +import numpy as np + + +def test_render_fragments(update: bool = False, display: bool = True) -> None: + obj_file = os.path.join(deodr.data_path, "duck.obj") + scene, camera = default_scene(obj_file, width=320, height=240) + image = scene.render(camera) + fragments = scene.render_fragments(camera) + x , y, alpha, values = fragments + + +if __name__ == "__main__": + test_render_fragments() diff --git a/tests/test_rgb_image_hand_fitting.py b/tests/test_rgb_image_hand_fitting.py index f383545..d74a0cd 100644 --- a/tests/test_rgb_image_hand_fitting.py +++ b/tests/test_rgb_image_hand_fitting.py @@ -81,5 +81,4 @@ def test_rgb_image_hand_fitting_tensorflow() -> None: if __name__ == "__main__": test_rgb_image_hand_fitting_tensorflow() test_rgb_image_hand_fitting_pytorch() - test_rgb_image_hand_fitting_numpy()