Conversion of PyQt implementation of drawEllipse into Matlab - python

I have a python program which draws some ellipses into a window. The following python code is used w
from PyQt4.QtGui import *
def draw_ellipse(self, center, rad_x, rad_y, angle, color):
qp = QtGui.QPainter()
qp.begin(self)
qp.translate(center)
qp.rotate(math.degrees(angle))
qp.setPen(QtGui.QColor(color))
qp.drawEllipse(QPoint(0, 0), rad_x, rad_y)
qp.end()
As you can see my input parameters are center, rad_x, rad_y and angle. These parameters are read in from a text file.
I want to use the very same parameter file in a Matlab program. For that I need to know the implementation of drawEllipse, so that I can implement the very same functionality in Matlab.
Unfortunately I don't seem to find the source code for drawEllipse. I found this link with the following code:
03114 {
03115 #ifdef QT_DEBUG_DRAW
03116 if (qt_show_painter_debug_output)
03117 printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
03118 #endif
03119
03120 if (!isActive())
03121 return;
03122 Q_D(QPainter);
03123 d->updateState(d->state);
03124
03125 QRectF rect(r.normalized());
03126
03127 if (rect.isEmpty())
03128 return;
03129
03130 if (d->state->emulationSpecifier) {
03131 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
03132 && d->state->txop == QPainterPrivate::TxTranslate) {
03133 rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
03134 } else {
03135 QPainterPath path;
03136 path.addEllipse(rect);
03137 d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
03138 return;
03139 }
03140 }
03141
03142 d->engine->drawEllipse(rect);
03143 }
Which leads me to this code (QPainterPath.addEllipse):
01052 void QPainterPath::addEllipse(const QRectF &boundingRect)
01053 {
01054 #ifndef QT_NO_DEBUG
01055 if (qIsNan(boundingRect.x()) || qIsNan(boundingRect.y())
01056 || qIsNan(boundingRect.width()) || qIsNan(boundingRect.height()))
01057 qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN, results are undefined");
01058 #endif
01059 if (boundingRect.isNull())
01060 return;
01061
01062 ensureData();
01063 detach();
01064
01065 Q_D(QPainterPath);
01066 d->elements.reserve(d->elements.size() + 13);
01067
01068 QPointF pts[12];
01069 int point_count;
01070 QPointF start = qt_curves_for_arc(boundingRect, 0, 360, pts, &point_count);
01071
01072 moveTo(start);
01073 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
01074 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
01075 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
01076 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
01077 d_func()->require_moveTo = true;
01078 }
So let's go into qstroker_8cpp and look at qt_curves_for_arc:
00722 QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,
00723 QPointF *curves, int *point_count)
00724 {
00725 Q_ASSERT(point_count);
00726 Q_ASSERT(curves);
00727
00728 #ifndef QT_NO_DEBUG
00729 if (qIsNan(rect.x()) || qIsNan(rect.y()) || qIsNan(rect.width()) || qIsNan(rect.height())
00730 || qIsNan(startAngle) || qIsNan(sweepLength))
00731 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");
00732 #endif
00733 *point_count = 0;
00734
00735 if (rect.isNull()) {
00736 return QPointF();
00737 }
00738
00739 if (sweepLength > 360) sweepLength = 360;
00740 else if (sweepLength < -360) sweepLength = -360;
00741
00742 // Special case fast path
00743 if (startAngle == 0.0 && sweepLength == 360.0) {
00744 qreal x = rect.x();
00745 qreal y = rect.y();
00746
00747 qreal w = rect.width();
00748 qreal w2 = rect.width() / 2;
00749 qreal w2k = w2 * QT_PATH_KAPPA;
00750
00751 qreal h = rect.height();
00752 qreal h2 = rect.height() / 2;
00753 qreal h2k = h2 * QT_PATH_KAPPA;
00754
00755 // 0 -> 270 degrees
00756 curves[(*point_count)++] = QPointF(x + w, y + h2 + h2k);
00757 curves[(*point_count)++] = QPointF(x + w2 + w2k, y + h);
00758 curves[(*point_count)++] = QPointF(x + w2, y + h);
00759
00760 // 270 -> 180 degrees
00761 curves[(*point_count)++] = QPointF(x + w2 - w2k, y + h);
00762 curves[(*point_count)++] = QPointF(x, y + h2 + h2k);
00763 curves[(*point_count)++] = QPointF(x, y + h2);
00764
00765 // 180 -> 90 degrees
00766 curves[(*point_count)++] = QPointF(x, y + h2 - h2k);
00767 curves[(*point_count)++] = QPointF(x + w2 - w2k, y);
00768 curves[(*point_count)++] = QPointF(x + w2, y);
00769
00770 // 90 -> 0 degrees
00771 curves[(*point_count)++] = QPointF(x + w2 + w2k, y);
00772 curves[(*point_count)++] = QPointF(x + w, y + h2 - h2k);
00773 curves[(*point_count)++] = QPointF(x + w, y + h2);
00774
00775 return QPointF(x + w, y + h2);
00776 }
00777
00778 #define ANGLE(t) ((t) * 2 * Q_PI / 360.0)
00779 #define SIGN(t) (t > 0 ? 1 : -1)
00780 qreal a = rect.width() / 2.0;
00781 qreal b = rect.height() / 2.0;
00782
00783 qreal absSweepLength = (sweepLength < 0 ? -sweepLength : sweepLength);
00784 int iterations = (int)ceil((absSweepLength) / 90.0);
00785
00786 QPointF first_point;
00787
00788 if (iterations == 0) {
00789 first_point = rect.center() + QPointF(a * qCos(ANGLE(startAngle)),
00790 -b * qSin(ANGLE(startAngle)));
00791 } else {
00792 qreal clength = sweepLength / iterations;
00793 qreal cosangle1, sinangle1, cosangle2, sinangle2;
00794
00795 for (int i=0; i<iterations; ++i) {
00796 qreal cangle = startAngle + i * clength;
00797
00798 cosangle1 = qCos(ANGLE(cangle));
00799 sinangle1 = qSin(ANGLE(cangle));
00800 cosangle2 = qCos(ANGLE(cangle + clength));
00801 sinangle2 = qSin(ANGLE(cangle + clength));
00802
00803 // Find the start and end point of the curve.
00804 QPointF startPoint = rect.center() + QPointF(a * cosangle1, -b * sinangle1);
00805 QPointF endPoint = rect.center() + QPointF(a * cosangle2, -b * sinangle2);
00806
00807 // The derived at the start and end point.
00808 qreal sdx = -a * sinangle1;
00809 qreal sdy = -b * cosangle1;
00810 qreal edx = -a * sinangle2;
00811 qreal edy = -b * cosangle2;
00812
00813 // Creating the tangent lines. We need to reverse their direction if the
00814 // sweep is negative (clockwise)
00815 QLineF controlLine1(startPoint, startPoint + SIGN(sweepLength) * QPointF(sdx, sdy));
00816 QLineF controlLine2(endPoint, endPoint - SIGN(sweepLength) * QPointF(edx, edy));
00817
00818 // We need to scale down the control lines to match that of the current sweeplength.
00819 // qAbs because we only want to scale, not change direction.
00820 qreal kappa = QT_PATH_KAPPA * qAbs(clength) / 90.0;
00821 // Adjust their length to fit the magic KAPPA length.
00822 controlLine1.setLength(controlLine1.length() * kappa);
00823 controlLine2.setLength(controlLine2.length() * kappa);
00824
00825 curves[(*point_count)++] = controlLine1.p2();
00826 curves[(*point_count)++] = controlLine2.p2();
00827 curves[(*point_count)++] = endPoint;
00828
00829 if (i == 0)
00830 first_point = startPoint;
00831 }
00832 }
00833
00834 return first_point;
00835 }
This is quite a lot of code for drawing a simple ellipse! It doesn't feel right to rewrite all of this in Matlab, if a simple ellipse can be plotted like this:
a = rad_x; % horizontal radius
b = rad_y; % vertical radius
x0 = center_x; % x0, y0 ellipse centre coordinates
y0 = center_y;
steps = 50;
t = linspace(0, 2*pi, steps);
theta0 = angle;
x = x0 + (a * sin(t - theta0));
y = y0 + (b * cos(t));
plot(x, y, '.-'),
Question:
given the four parameters listed above (center, rad_x, rad_y and angle), what's the easiest way for me to plot the ellipse correctly in matlab? With my matlab code above plotting currently only works for small angles and particular rad_x & rad_y combinations.

How about something like this?
a = rad_x;
b = rad_y;
r0 = center_x + i*center_y; % <-- origin of ellipse
theta0=angle; % <-- angle of rotation of ellipse
steps = 200;
t = linspace(0, 2*pi, steps);
r = a*sin(t) + i*b*cos(t);
R = exp(i*theta0);
r = R*r;
r = r0 + r;
figure(1), hold on
plot(real(r), imag(r), '-r')
Using matrices rather than complex numbers:
a = rad_x;
b = rad_y;
r0 = [center_x ; center_y]; % <-- origin of ellipse
theta0=angle; % <-- angle of rotation of ellipse
steps = 200;
t = linspace(0, 2*pi, steps);
r = [a*sin(t) ; b*cos(t)];
R = [cos(theta0) -sin(theta0) ; sin(theta0) cos(theta0)]; % <-- note neg signs: define direction of rotation!
r = R*r;
r = r0*ones(1,length(t)) + r;
figure(1)
plot(r(1,:), r(2,:), '-r')

Related

Boost.Python + opencv Error, Windows 10 x64, "ImportError: DLL load failed: The specified module could not be found."

I am a beginner in C++ and python. I have installed boost-1.78.0, OPENCV-4.5.5 and added a new Dynamic-Link Library (DLL) project in Visual Studio 2019, and then successfully build the sln and generated testSqaure.dll.
My code is as follows:
#define BOOST_PYTHON_STATIC_LIB
#include "pch.h"
#include<boost/python.hpp>
#include<boost/python/numpy.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<cmath>
#include<algorithm>
using boost::python::list;
using boost::python::numpy::ndarray;
using boost::python::object;
using boost::python::extract;
using std::vector;
using std::array;
using std::sqrt;
using std::min;
using cv::Point2f;
using cv::Point;
using cv::pointPolygonTest;
vector<double> ndarray2vec(const ndarray& arr)
{
int input_size = static_cast<int>(arr.shape(0));
double* input_ptr = reinterpret_cast<double*>(arr.get_data());
vector<double> v_arr(input_size);
for (int i = 0; i < input_size; ++i)
{
v_arr[i] = *(input_ptr + i);
}
return v_arr;
}
bool two_line_segment_test(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
if (((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)) == 0) return false;
const double px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
const double py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
if ((((x1 <= px) && (px <= x2)) || ((x2 <= px) && (px <= x1))) && (((x3 <= px) && (px <= x4)) || ((x4 <= px) && (px <= x3))) && (((y1 <= py) && (py <= y2)) || ((y2 <= py) && (py <= y1))) && (((y3 <= py) && (py <= y4)) || ((y4 <= py) && (py <= y3))))
{
return true;
}
else return false;
}
object two_triangle_test(ndarray& tri1_side1, ndarray& tri1_side2, ndarray& tri1_side3, ndarray& tri2_side1, ndarray& tri2_side2, ndarray& tri2_side3)
{
vector<double> v_tri1_side1 = ndarray2vec(tri1_side1),
v_tri1_side2 = ndarray2vec(tri1_side2),
v_tri1_side3 = ndarray2vec(tri1_side3),
v_tri2_side1 = ndarray2vec(tri2_side1),
v_tri2_side2 = ndarray2vec(tri2_side2),
v_tri2_side3 = ndarray2vec(tri2_side3);
array<vector<double>, 3> v_tri1_sides = { v_tri1_side1, v_tri1_side2, v_tri1_side3 };
array<vector<double>, 3> v_tri2_sides = { v_tri2_side1, v_tri2_side2, v_tri2_side3 };
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (two_line_segment_test(v_tri1_sides[i][0], v_tri1_sides[i][1], v_tri1_sides[i][2], v_tri1_sides[i][3], v_tri2_sides[j][0], v_tri2_sides[j][1], v_tri2_sides[j][2], v_tri2_sides[j][3]))
{
return object(true);
}
}
}
vector<Point2f> tri1(3);
tri1[0] = Point(v_tri1_side1[0], v_tri1_side1[1]);
tri1[1] = Point(v_tri1_side1[2], v_tri1_side1[3]);
tri1[2] = Point(v_tri1_side2[2], v_tri1_side2[3]);
for (auto& side : v_tri2_sides)
{
const int retval = static_cast<int>(pointPolygonTest(tri1, Point(side[0], side[1]), false));
if (retval == 1 || retval == 0) return object(true);
}
vector<Point2f> tri2(3);
tri2[0] = Point(v_tri2_side1[0], v_tri2_side1[1]);
tri2[1] = Point(v_tri2_side1[2], v_tri2_side1[3]);
tri2[2] = Point(v_tri2_side2[2], v_tri2_side2[3]);
for (auto& side : v_tri1_sides)
{
const int retval = static_cast<int>(pointPolygonTest(tri2, Point(side[0], side[1]), false));
if (retval == 1 || retval == 0) return object(true);
}
return object(false);
}
array<double, 2> get_foot_point(const vector<double>& v_point, const vector<double>& v_line_p1, const vector<double>& v_line_p2)
{
const double k = -((v_line_p1[0] - v_point[0]) * (v_line_p2[0] - v_line_p1[0]) + (v_line_p1[1] - v_point[0]) * (v_line_p2[1] - v_line_p1[1]) + 0) / ((v_line_p2[0] - v_line_p1[0]) * (v_line_p2[0] - v_line_p1[0]) + (v_line_p2[1] - v_line_p1[1]) * (v_line_p2[1] - v_line_p1[1]) + 0) * 1.0;
const double xn = k * (v_line_p2[0] - v_line_p1[0]) + v_line_p1[0];
const double yn = k * (v_line_p2[1] - v_line_p1[1]) + v_line_p1[1];
return array<double, 2>{xn, yn};
}
double get_dis_point2line(const vector<double>& v_point, const vector<double>& v_line_p1, const vector<double>& v_line_p2)
{
array<double, 2> footP = get_foot_point(v_point, v_line_p1, v_line_p2);
double dist = 0;
if (((footP[0] - v_line_p1[0]) > 0) ^ ((footP[0] - v_line_p2[0]) > 0))
{
dist = sqrt((footP[0] - v_point[0]) * (footP[0] - v_point[0]) + (footP[1] - v_point[1]) * (footP[1] - v_point[1]));
}
else
{
dist = min(sqrt((v_line_p1[0] - v_point[0]) * (v_line_p1[0] - v_point[0]) + (v_line_p1[1] - v_point[1]) * (v_line_p1[1] - v_point[1])),
sqrt((v_line_p2[0] - v_point[0]) * (v_line_p2[0] - v_point[0]) + (v_line_p2[1] - v_point[1]) * (v_line_p2[1] - v_point[1])));
}
return dist;
}
object circle_triangle_test(const ndarray& center, const object& radius, const ndarray& tri_side1, const ndarray& tri_side2, const ndarray& tri_side3)
{
const double val_radius = extract<double>(radius);
vector<double> v_tri_side1 = ndarray2vec(tri_side1),
v_tri_side2 = ndarray2vec(tri_side2),
v_tri_side3 = ndarray2vec(tri_side3),
v_center = ndarray2vec(center);
array<vector<double>, 3> v_tri_sides = { v_tri_side1, v_tri_side2, v_tri_side3 };
for (int i = 0; i < 3; ++i)
{
if (sqrt((v_tri_sides[i][0] - v_center[0]) * (v_tri_sides[i][0] - v_center[0]) + (v_tri_sides[i][1] - v_center[1]) * (v_tri_sides[i][1] - v_center[1])) <= val_radius)
{
return object(true);
}
}
for (int i = 0; i < 3; ++i)
{
if (get_dis_point2line(v_center, { v_tri_sides[i][0], v_tri_sides[i][1] }, { v_tri_sides[i][2], v_tri_sides[i][3] }) <= val_radius)
{
return object(true);
}
}
return object(false);
}
BOOST_PYTHON_MODULE(testSquare)
{
using namespace boost::python;
def("two_triangle_test", two_triangle_test);
def("circle_triangle_test", circle_triangle_test);
}
This file mainly writes two functions, which are used to detect whether two triangles overlap, and whether a circle overlaps another triangle.
But when I rename testSquare.dll to testSquare.pyd and import it in a .py file, I found that there is a error: "ImportError: DLL load failed: The specified module could not be found."
The DLL file generated by boost example.cpp like this can be imported and used correctly:
#include "pch.h"
#define BOOST_PYTHON_STATIC_LIB
#include<boost/python.hpp>
using boost::python::list;
list Square(list& data)
{
list ret;
for (int i = 0; i < len(data); ++i)
{
ret.append(data[i] * data[i]);
}
return ret;
}
BOOST_PYTHON_MODULE(testSquare)
{
using namespace boost::python;
def("Square", Square);
}
I have solved this problem by moving boost_python37-vc142-mt-gd-x64-1_78.dll and boost_numpy37-vc142-mt-gd-x64-1_78.dll to the project folder, or by putting the paths like D:\Data\dev\boost_1_78_0\stage\lib where they are in PATH.
The routine for configuring boost doesn't tell me to put this path into PATH.

Any method like np.concatenate to use in c++?

I recently study with Dicom images deep learning. I want to move my dicom image processing code from python to c++.
Following is my python code.
def window_img(dcm, width=None, level=None):
pixels = dcm.pixel_array * dcm.RescaleSlope + dcm.RescaleIntercept
lower = level - (width / 2)
upper = level + (width / 2)
pixels[pixels<lower] = lower
pixels[pixels>upper] = upper
pixels = (pixels - (level - width//2)) / width
return pixels
def meta_dicom_convert(dcm, ww, wc):
b = window_img(dcm, ww[0], wc[0])
g = window_img(dcm, ww[1], wc[1])
r = window_img(dcm, ww[2], wc[2])
image = np.concatenate([b, g, r], axis=2)
return image
And I try to do something like this in c++. However, I only found some method like cv::merge. I use cv::merge. But it seems a little differet from images combined by np.concatenate.
My C++ code:
DcmFileFormat dfile;
OFCondition result = dfile.loadFile("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
DcmDataset *dcmdataset = dfile.getDataset();
double slope, intercept;
dcmdataset->findAndGetFloat64(DCM_RescaleSlope, slope);
dcmdataset->findAndGetFloat64(DCM_RescaleIntercept, intercept);
DicomImage dcmimage_brain("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
DicomImage dcmimage_subdural("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
DicomImage dcmimage_bone("D:\\python\\RSNA\\stage_2_train\\ID_c8355f255.dcm");
int nWidth = dcmimage_brain.getWidth();
int nHeight = dcmimage_brain.getHeight();
cout << "size = " << nWidth << " x " << nHeight << endl;
int wcenter = 40, wwidth = 80;
int lower = wcenter - (wwidth / 2);
int upper = wcenter + (wwidth / 2);
dcmimage_brain.setWindow(wcenter, wwidth);
Uint8 *pixeldata_brain = (Uint8*)(dcmimage_brain.getOutputData(8));
if (pixeldata_brain)
{
for (int i = 0; i < nWidth * nHeight; ++i) {
if (pixeldata_brain[i] < lower)
pixeldata_brain[i] = lower;
if (pixeldata_brain[i] > upper)
pixeldata_brain[i] = upper;
pixeldata_brain[i] = (255 * (pixeldata_brain[i] - lower)) / (upper - lower);
}
}
Mat brain = Mat(nWidth, nHeight, CV_8UC1, pixeldata_brain);
//brain.convertTo(brain, CV_8UC1);
wcenter = 80;
wwidth = 200;
lower = wcenter - (wwidth / 2);
upper = wcenter + (wwidth / 2);
dcmimage_subdural.setWindow(wcenter, wwidth);
Uint8 *pixeldata_subdural = (Uint8*)(dcmimage_subdural.getOutputData(8));
if (pixeldata_subdural)
{
for (int i = 0; i < nWidth * nHeight; ++i) {
if (pixeldata_subdural[i] < lower)
pixeldata_subdural[i] = lower;
if (pixeldata_subdural[i] > upper)
pixeldata_subdural[i] = upper;
pixeldata_subdural[i] = (255 * (pixeldata_subdural[i] - lower)) / (upper - lower);
}
}
Mat subdural = Mat(nWidth, nHeight, CV_8UC1, pixeldata_subdural);
//subdural.convertTo(subdural, CV_8UC1);
wcenter = 40;
wwidth = 380;
lower = wcenter - (wwidth / 2);
upper = wcenter + (wwidth / 2);
dcmimage_bone.setWindow(wcenter, wwidth);
Uint8 *pixeldata_bone = (Uint8*)(dcmimage_bone.getOutputData(8));
if (pixeldata_bone) {
for (int i = 0; i < nWidth * nHeight; ++i) {
if (pixeldata_bone[i] < lower)
pixeldata_bone[i] = lower;
if (pixeldata_bone[i] > upper)
pixeldata_bone[i] = upper;
pixeldata_bone[i] = (255 * (pixeldata_bone[i] - lower) / (upper - lower));
}
}
Mat bone = Mat(nWidth, nHeight, CV_8UC1, pixeldata_bone);
imshow("bone", bone);
//bone.convertTo(bone, CV_8UC1);
//Mat bone = Mat(nWidth, nHeight, CV_16UC1, pbone);
//bone.convertTo(bone, CV_8UC1);
// new Image size
Mat image = Mat::zeros(nWidth, nHeight, CV_8UC3);
vector<Mat> channels;
split(image, channels);
channels.at(0) = brain;
channels.at(1) = subdural;
channels.at(2) = bone;
merge(channels, image);
imshow("mergeImage", image);
waitKey();
result image: (left side: cv::merge) (right side: np.concatenate)
enter image description here
Is cv::merge actually not just concatenate images in channels?
Is there any other method I can use in c++ to do thing like np.concatenate?
Any reply would be appreciate. thanks

CUDA: does size of input/output data have to be a multiple of the number of threads per block?

I have a Python code (for implementing RayTracing) that I'm running in parallel with PyCuda.
import pycuda.driver as drv
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
from stl import mesh
import time
my_mesh = mesh.Mesh.from_file('test_solid_py.stl')
n = my_mesh.normals
v0 = my_mesh.v0
v1 = my_mesh.v1
v2 = my_mesh.v2
v0_x = v0[:,0]
v0_x = np.ascontiguousarray(v0_x)
v0_y = v0[:,1]
v0_y = np.ascontiguousarray(v0_y)
v0_z = v0[:,2]
v0_z = np.ascontiguousarray(v0_z)
v1_x = v1[:,0]
v1_x = np.ascontiguousarray(v1_x)
v1_y = v1[:,1]
v1_y = np.ascontiguousarray(v1_y)
v1_z = v1[:,2]
v1_z = np.ascontiguousarray(v1_z)
v2_x = v2[:,0]
v2_x = np.ascontiguousarray(v2_x)
v2_y = v2[:,1]
v2_y = np.ascontiguousarray(v2_y)
v2_z = v2[:,2]
v2_z = np.ascontiguousarray(v2_z)
mod = SourceModule("""
#include <math.h>
__global__ void intersect(float *origin,float *dir_x,float *dir_y,float *dir_z,float *v0_x,float *v0_y,float *v0_z,float *v1_x,float *v1_y,float *v1_z,float *v2_x,float *v2_y,float *v2_z,float *int_point_real_x, float *int_point_real_y,float *int_point_real_z)
{
using namespace std;
unsigned int idx = blockDim.x*blockIdx.x + threadIdx.x;
int count = 0;
float v0_current[3];
float v1_current[3];
float v2_current[3];
float dir_current[3] = {dir_x[idx],dir_y[idx],dir_z[idx]};
float int_point[3];
float int_pointS[2][3];
int int_faces[2];
float dist[2];
dist[0] = -999;
int n_tri = 105500;
for(int i = 0; i<n_tri; i++) {
v0_current[0] = v0_x[i];
v0_current[1] = v0_y[i];
v0_current[2] = v0_z[i];
v1_current[0] = v1_x[i];
v1_current[1] = v1_y[i];
v1_current[2] = v1_z[i];
v2_current[0] = v2_x[i];
v2_current[1] = v2_y[i];
v2_current[2] = v2_z[i];
double eps = 0.0000001;
float E1[3];
float E2[3];
float s[3];
for (int j = 0; j < 3; j++) {
E1[j] = v1_current[j] - v0_current[j];
E2[j] = v2_current[j] - v0_current[j];
s[j] = origin[j] - v0_current[j];
}
float h[3];
h[0] = dir_current[1] * E2[2] - dir_current[2] * E2[1];
h[1] = -(dir_current[0] * E2[2] - dir_current[2] * E2[0]);
h[2] = dir_current[0] * E2[1] - dir_current[1] * E2[0];
float a;
a = E1[0] * h[0] + E1[1] * h[1] + E1[2] * h[2];
if (a > -eps && a < eps) {
int_point[0] = false;
}
else {
double f = 1 / a;
float u;
u = f * (s[0] * h[0] + s[1] * h[1] + s[2] * h[2]);
if (u < 0 || u > 1) {
int_point[0] = false;
}
else {
float q[3];
q[0] = s[1] * E1[2] - s[2] * E1[1];
q[1] = -(s[0] * E1[2] - s[2] * E1[0]);
q[2] = s[0] * E1[1] - s[1] * E1[0];
float v;
v = f * (dir_current[0] * q[0] + dir_current[1] * q[1] + dir_current[2] * q[2]);
if (v < 0 || (u + v)>1) {
int_point[0] = false;
}
else {
float t;
t = f * (E2[0] * q[0] + E2[1] * q[1] + E2[2] * q[2]);
if (t > eps) {
for (int j = 0; j < 3; j++) {
int_point[j] = origin[j] + dir_current[j] * t;
}
//return t;
}
}
}
}
if (int_point[0] != false) {
count = count+1;
int_faces[count-1] = i;
dist[count-1] = sqrt(pow((origin[0] - int_point[0]), 2) + pow((origin[1] - int_point[1]), 2) + pow((origin[2] - int_point[2]), 2));
for (int j = 0; j<3; j++) {
int_pointS[count-1][j] = int_point[j];
}
}
}
double min = dist[0];
int ind_min = 0;
for (int i = 0; i < 2; i++){
if (min > dist[i]) {
min = dist[i];
ind_min = i;
}
}
if (dist[0] < -998){
int_point_real_x[idx] = -999;
int_point_real_y[idx] = -999;
int_point_real_z[idx] = -999;
}
else{
int_point_real_x[idx] = int_pointS[ind_min][0];
int_point_real_y[idx] = int_pointS[ind_min][1];
int_point_real_z[idx] = int_pointS[ind_min][2];
}
}
""")
n_rays = 20000
num_threads = 1024
num_blocks = int(n_rays/num_threads)
origin = np.asarray([-2, -2, -2]).astype(np.float32)
origin = np.ascontiguousarray(origin)
rand_x = np.random.randn(n_rays)
rand_y = np.random.randn(n_rays)
rand_z = np.random.randn(n_rays)
direction_x = np.ones((n_rays, 1)) * 3
direction_x = direction_x.astype(np.float32)
direction_x = np.ascontiguousarray(direction_x)
direction_y = np.ones((n_rays, 1)) * 4
direction_y = direction_y.astype(np.float32)
direction_y = np.ascontiguousarray(direction_y)
direction_z = np.ones((n_rays, 1)) * 5
direction_z = direction_z.astype(np.float32)
direction_z = np.ascontiguousarray(direction_z)
int_point_real_x = np.zeros((n_rays, 1)).astype(np.float32)
int_point_real_x = np.ascontiguousarray(int_point_real_x)
int_point_real_y = np.zeros((n_rays, 1)).astype(np.float32)
int_point_real_y = np.ascontiguousarray(int_point_real_y)
int_point_real_z = np.zeros((n_rays, 1)).astype(np.float32)
int_point_real_z = np.ascontiguousarray(int_point_real_z)
intersect = mod.get_function("intersect")
start = time.time()
intersect(drv.In(origin), drv.In(direction_x),drv.In(direction_y),drv.In(direction_z),drv.In(v0_x),drv.In(v0_y),drv.In(v0_z), drv.In(v1_x),drv.In(v1_y),drv.In(v1_z), drv.In(v2_x), drv.In(v2_y), drv.In(v2_z), drv.Out(int_point_real_x),drv.Out(int_point_real_y),drv.Out(int_point_real_z), block=(num_threads, 1, 1), grid=((num_blocks+0), 1, 1))
finish = time.time()
print(finish-start)
I give as input some arrays whose size is 20k (dir_x, dir_y, dir_z) and I have as output 3 arrays (int_point_real_x,int_point_real_y,int_point_real_z) that have the same size as the above mentioned arrays (20k).
If n_rays is a multiple of num_threads, e.g. n_rays=19456 and num_threads=1024, then int_point_real_x_y_z are correctly filled by the kernel.
Otherwise, if n_rays is NOT a multiple of num_threads, e.g. n_rays=20000 (what I really need) and num_threads=1024, then int_point_real_x_y_z are filled by the kernel up to position 19455 and the 544 spots left in the array are not filled.
Does anyone know if this is a rule of CUDA?
If it's not, how could I modify my code in order to use an arbitrary size of input array (and not only multiple of num_threads)?
Thanks
your int(n_rays/num_threads) is rounding down
to fix this, you need to round up and then put a condition into the kernel to enforce that idx is valid and "do nothing" if it's not. this will cause some cores to waste time, but your code looks pretty suboptimal anyway so it probably won't matter much

How to repeat an animation in plotly

I am using the example from:
https://plot.ly/python/filled-area-animation/
How can I play the animation repeatedly?
So once the play button is clicked it will continue playing repeatedly?
Another option is to have the animation play non stop once the animation is loaded.
One solution can be found here. The idea is that instead of passing all frames beforehand you create them on the fly using the update function.
The plot is created with Plotly.animate().
You can also change this example to fit your case. Iterate through your list of data points. Once you reach the end of your array, set the counter to 0 to start at the beginning.
This example uses redraw: false, which can be used to update the plot at high frame rates.
var n = 100;
var x = [], y = [], z = [];
var dt = 0.015;
for (i = 0; i < n; i++) {
x[i] = Math.random() * 2 - 1;
y[i] = Math.random() * 2 - 1;
z[i] = 30 + Math.random() * 10;
}
Plotly.plot('graph', [{
x: x,
y: z,
mode: 'markers'
}], {
xaxis: {range: [-40, 40]},
yaxis: {range: [0, 60]}
})
function compute () {
var s = 10, b = 8/3, r = 28;
var dx, dy, dz;
var xh, yh, zh;
for (var i = 0; i < n; i++) {
dx = s * (y[i] - x[i]);
dy = x[i] * (r - z[i]) - y[i];
dz = x[i] * y[i] - b * z[i];
xh = x[i] + dx * dt * 0.5;
yh = y[i] + dy * dt * 0.5;
zh = z[i] + dz * dt * 0.5;
dx = s * (yh - xh);
dy = xh * (r - zh) - yh;
dz = xh * yh - b * zh;
x[i] += dx * dt;
y[i] += dy * dt;
z[i] += dz * dt;
}
}
function update () {
compute();
Plotly.animate('graph', {
data: [{x: x, y: z}]
}, {
transition: {
duration: 0
},
frame: {
duration: 0,
redraw: false
}
});
requestAnimationFrame(update);
}
requestAnimationFrame(update);

OpenCV Inverse Matrix

somehow I get different results using numpy's linalg.inv and OpenCv's Mat::inv, e.g. given a matrix S:
[747.8561839552103, 359.9317804054358, 204.6165451419812, 241.7376332155144, 126.132733370211, 81.57610562583466;
359.9317804054358, 204.6165451419812, 140.4788277943211, 126.132733370211, 80.55127348381332, 47.7506303038364;
204.6165451419812, 140.4788277943211, 116.7472083846913, 80.55127348381332, 63.86033402962857, 35.56970826526131;
241.7376332155144, 126.132733370211, 80.55127348381332, 81.57610562583466, 47.7506303038364, 29.55106507912703;
126.132733370211, 80.55127348381332, 63.86033402962857, 47.7506303038364, 35.56970826526131, 20.31193086803655;
81.57610562583466, 47.7506303038364, 35.56970826526131, 29.55106507912703, 20.31193086803655, 12]
OpenCV S.inv() results in
[-19562262532715.65, 137.3094415699439, -44015090698406.93, 78249050130618.84, 88030181396160.73, -78249050129617.47;
124.2797501878658, 19.14093204142484, 301.2737811201993, -531.0713785028685, -686.3332686269306, 655.5356524828615;
-44015090698424.45, 330.6065529853437, -99033954070961.39, 176060362793110.9, 198067908140346.2, -176060362790691.7;
78249050130642.06, -583.2397919514979, 176060362793093.2, -312996200521532.5, -352120725583424.9, 312996200517305.3;
88030181396256.19, -744.9706630355842, 198067908140482.2, -352120725583702.1, -396135816277430.2, 352120725578288.9;
-78249050129732.52, 707.7008280168318, -176060362790880.5, 312996200517672.6, 352120725578424.8, -312996200512573.6]
numpy's linalg.inv results in:
[[2685109332201.37, -23.46, 6041495997420.42, -10740437328763.82, -12082991994731.51, 10740437328597.41]
[-32.56, 19.14, -51.60, 96.23, 19.43, 28.24]
[6041495997407.60, -31.13, 13593365994129.85, -24165983989574.97, -27186731988120.73, 24165983989366.80]
[-10740437328747.65, 59.84, -24165983989589.86, 42961749314884.59, 48331967978891.43, -42961749314440.71]
[-12082991994663.29, -21.50, -27186731988024.93, 48331967978691.32, 54373463976152.90, -48331967978849.60]
[10740437328516.33, 64.62, 24165983989235.66, -42961749314181.06, -48331967978757.62, 42961749314608.99]]
Okay, now some detail of how I stumbled across this:
I am working on a routine to fit an ellipse given a point set; I have transferred code from: http://nicky.vanforeest.com/misc/fitEllipse/fitEllipse.html to C++:
template <typename InputIt>
std::array<double, 6> fit_ellipse(InputIt first, InputIt last) {
typedef double value_type;
auto num_points = std::distance(first, last);
cv::Mat_<value_type> D(num_points, 6);
size_t row(0);
for (auto it(first); it != last; ++it, ++row) {
auto &point = *it;
auto &x = std::get<0>(point);
auto &y = std::get<1>(point);
D(row, 0) = x * x;
D(row, 1) = x * y;
D(row, 2) = y * y;
D(row, 3) = x;
D(row, 4) = y;
D(row, 5) = 1.f;
}
auto S = D.t() * D;
cv::Mat_<value_type> C = cv::Mat_<value_type>::zeros(6, 6);
C(0, 2) = C(2, 0) = 2; C(1, 1) = -1;
cv::Mat Sinv = S.inv();
std::cout << "Sinv:" << Sinv << std::endl;
cv::Mat_<value_type> E, V; cv::eigen(Sinv * C, E, V);
int n;
cv::minMaxIdx(cv::abs(E), nullptr, nullptr, nullptr, &n);
return {{V(n, 0), V(n, 1), V(n, 2), V(n, 3), V(n, 4), V(n, 5)}};
}
To comparison the Python code:
import numpy as np
from numpy.linalg import eig, inv
def fitEllipse(x,y):
x = x[:,np.newaxis]
y = y[:,np.newaxis]
D = np.hstack((x*x, x*y, y*y, x, y, np.ones_like(x)))
S = np.dot(D.T,D)
C = np.zeros([6,6])
C[0,2] = C[2,0] = 2; C[1,1] = -1
Sinv = inv(S)
print("Sinv: %s" % Sinv)
E, V = eig(np.dot(Sinv, C))
n = np.argmax(np.abs(E))
a = V[:,n]
return a
The code is run initializing following points:
TEST(fit_ellipse, test_example) {
namespace bmc = boost::math::constants;
typedef std::array<double, 2> point_type;
std::vector<point_type> points;
auto arc = .8;
for (size_t i(0); i < 12; ++i) {
auto r = i * arc * bmc::pi<double>() / 12;
points.push_back({1.5 * std::cos(r) + 2, std::sin(r) + 1});
}
auto a = fit_ellipse(points.begin(), points.end());
std::cout << "Parameters: "
for (auto &p : a)
std::cout << p << ' ';
std::cout << std::endl;
}
Same in Python:
R = np.arange(0, arc * np.pi, arc * np.pi / 12)
x = 1.5 * np.cos(R) + 2
y = np.sin(R) + 1.
print("Parameters: %s" % fitEllipse(x,y))
Any Idea what I am missing out?

Categories