Commit bd1cdf2d authored by André Anjos's avatar André Anjos 💬
Browse files

Add line drawing support; Fix tests

parent 275e7480
......@@ -45,6 +45,7 @@ setup(
),
Extension("xbob.ip.draw._library",
[
"xbob/ip/draw/line.cpp",
"xbob/ip/draw/point.cpp",
"xbob/ip/draw/try_point.cpp",
"xbob/ip/draw/main.cpp",
......
/**
* @file ip/python/drawing.cc
* @date Sun Jul 24 21:13:21 2011 +0200
* @author Andre Anjos <andre.anjos@idiap.ch>
*
* @brief Binds simple drawing primitives
*
* Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland
*/
#include <bob/python/ndarray.h>
#include <bob/ip/drawing.h>
using namespace boost::python;
template <typename T>
static void inner_draw_point_ (bob::python::ndarray image, int y, int x, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::draw_point_(image_, y, x, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::draw_point_(image_, y, x, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void draw_point_ (bob::python::ndarray image, int y, int x, object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_draw_point_<uint8_t>(image, y, x, color);
case bob::core::array::t_uint16: return inner_draw_point_<uint16_t>(image, y, x, color);
case bob::core::array::t_float64: return inner_draw_point_<double>(image, y, x, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
template <typename T>
static void inner_draw_point (bob::python::ndarray image, int y, int x, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::draw_point(image_, y, x, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::draw_point(image_, y, x, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void draw_point (bob::python::ndarray image, int y, int x, object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_draw_point<uint8_t>(image, y, x, color);
case bob::core::array::t_uint16: return inner_draw_point<uint16_t>(image, y, x, color);
case bob::core::array::t_float64: return inner_draw_point<double>(image, y, x, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
template <typename T>
static void inner_try_draw_point (bob::python::ndarray image, int y, int x, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::try_draw_point(image_, y, x, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::try_draw_point(image_, y, x, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void try_draw_point (bob::python::ndarray image, int y, int x, object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_try_draw_point<uint8_t>(image, y, x, color);
case bob::core::array::t_uint16: return inner_try_draw_point<uint16_t>(image, y, x, color);
case bob::core::array::t_float64: return inner_try_draw_point<double>(image, y, x, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
template <typename T>
static void inner_draw_line (bob::python::ndarray image, int y1, int x1, int y2, int x2, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::draw_line(image_, y1, x1, y2, x2, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::draw_line(image_, y1, x1, y2, x2, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void draw_line (bob::python::ndarray image, int y1, int x1, int y2, int x2, object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_draw_line<uint8_t>(image, y1, x1, y2, x2, color);
case bob::core::array::t_uint16: return inner_draw_line<uint16_t>(image, y1, x1, y2, x2, color);
case bob::core::array::t_float64: return inner_draw_line<double>(image, y1, x1, y2, x2, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
template <typename T>
static void inner_draw_cross (bob::python::ndarray image, int y, int x, int radius, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::draw_cross(image_, y, x, radius, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::draw_cross(image_, y, x, radius, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void draw_cross (bob::python::ndarray image, int y, int x, int radius,
object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_draw_cross<uint8_t>(image, y, x, radius, color);
case bob::core::array::t_uint16: return inner_draw_cross<uint16_t>(image, y, x, radius, color);
case bob::core::array::t_float64: return inner_draw_cross<double>(image, y, x, radius, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
template <typename T>
static void inner_draw_cross_plus (bob::python::ndarray image, int y, int x, int radius, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::draw_cross_plus(image_, y, x, radius, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::draw_cross_plus(image_, y, x, radius, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void draw_cross_plus (bob::python::ndarray image, int y, int x, int radius,
object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_draw_cross_plus<uint8_t>(image, y, x, radius, color);
case bob::core::array::t_uint16: return inner_draw_cross_plus<uint16_t>(image, y, x, radius, color);
case bob::core::array::t_float64: return inner_draw_cross_plus<double>(image, y, x, radius, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
template <typename T>
static void inner_draw_box (bob::python::ndarray image, int y, int x, int h, int w, object color) {
switch (image.type().nd) {
case 2:
{
blitz::Array<T,2> image_ = image.bz<T,2>();
T tcolor = extract<T>(color);
bob::ip::draw_box(image_, y, x, h, w, tcolor);
}
break;
case 3:
{
blitz::Array<T,3> image_ = image.bz<T,3>();
tuple c = extract<tuple>(color);
T c0 = extract<T>(c[0]);
T c1 = extract<T>(c[1]);
T c2 = extract<T>(c[2]);
boost::tuple<T,T,T> tcolor(c0, c1, c2);
bob::ip::draw_box(image_, y, x, h, w, tcolor);
}
break;
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", image.type().str().c_str());
}
}
static void draw_box (bob::python::ndarray image, int y, int x, int h, int w,
object color) {
const bob::core::array::typeinfo& info = image.type();
switch(info.dtype) {
case bob::core::array::t_uint8: return inner_draw_box<uint8_t>(image, y, x, h, w, color);
case bob::core::array::t_uint16: return inner_draw_box<uint16_t>(image, y, x, h, w, color);
case bob::core::array::t_float64: return inner_draw_box<double>(image, y, x, h, w, color);
default: PYTHON_ERROR(TypeError, "drawing operation does not support '%s'", info.str().c_str());
}
}
void bind_ip_drawing() {
def("draw_point_", &draw_point_, (arg("image"), arg("y"), arg("x"), arg("color")), "Draws a point in an image. No checks, if you try to access an area outside the image using this method, you may trigger a segmentation fault. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_point", &draw_point, (arg("image"), arg("y"), arg("x"), arg("color")), "Draws a point in the given image. Trying to access outside the image range will raise an exception. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("try_draw_point", try_draw_point, (arg("image"), arg("y"), arg("x"), arg("color")), "Tries to draw a point at the given image. If the point is out of range, just ignores the request. This is what is used for drawing lines. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_line", &draw_line, (arg("image"), arg("y1"), arg("x1"), arg("y2"), arg("x2"), arg("color")), "Draws a line between two points p1(x1,y1) and p2(x2,y2). This function is based on the Bresenham's line algorithm and is highly optimized to be able to draw lines very quickly. There is no floating point arithmetic nor multiplications and divisions involved. Only addition, subtraction and bit shifting are used.\n\nThe line may go out of the image bounds in which case such points (lying outside the image boundary are ignored).\n\nReferences: http://en.wikipedia.org/wiki/Bresenham's_line_algorithm. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_cross", &draw_cross, (arg("image"), arg("y"), arg("x"), arg("radius"), arg("color")), "Draws a cross with a given radius and color at the image. Uses the draw_line() primitive above. The cross will look like an 'x' and not like a '+'. To get a '+' sign, use the draw_cross_plus() variant. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_cross_plus", &draw_cross_plus, (arg("image"), arg("y"), arg("x"), arg("radius"), arg("color")), "Draws a cross with a given radius and color at the image. Uses the draw_line() primitive above. The cross will look like an '+' and not like a 'x'. To get a 'x' sign, use the draw_cross() variant. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_box", &draw_box, (arg("image"), arg("y"), arg("x"), arg("height"), arg("width"), arg("color")), "Draws a box at the image using the draw_line() primitive. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
}
/**
* @author André Anjos <andre.anjos@idiap.ch>
* @date Mon 7 Apr 17:57:11 2014 CEST
*
* @brief Binds point drawing operator to Python
*
* Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
*/
#include <xbob.blitz/cppapi.h>
#include <xbob.blitz/cleanup.h>
#include <boost/tuple/tuple.hpp>
#include <bob/ip/drawing.h>
#include "utils.h"
template <typename T>
static PyObject* inner_line (PyBlitzArrayObject* image,
Py_ssize_t y1, Py_ssize_t x1, Py_ssize_t y2, Py_ssize_t x2, PyObject* color) {
switch (image->ndim) {
case 2:
{
T c;
int ok = get_color1(color, c);
if (!ok) return 0;
try {
bob::ip::draw_line(*PyBlitzArrayCxx_AsBlitz<T,2>(image), y1, x1,
y2, x2, c);
}
catch (std::exception& e) {
PyErr_Format(PyExc_RuntimeError, "%s", e.what());
return 0;
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "caught unknown exception while calling C++ bob::ip::draw_line");
return 0;
}
}
break;
case 3:
{
T r, g, b;
int ok = get_color3(color, r, g, b);
if (!ok) return 0;
try {
bob::ip::draw_line(*PyBlitzArrayCxx_AsBlitz<T,3>(image), y1, x1,
y2, x2, boost::tuple<T,T,T>(r, g, b));
}
catch (std::exception& e) {
PyErr_Format(PyExc_RuntimeError, "%s", e.what());
return 0;
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "caught unknown exception while calling C++ bob::ip::draw_point");
return 0;
}
}
break;
default:
PyErr_Format(PyExc_TypeError, "drawing operation does not support images with %" PY_FORMAT_SIZE_T "d dimensions (1 or 3 only)", image->ndim);
return 0;
}
Py_RETURN_NONE;
}
PyObject* PyBobIpDraw_Line (PyObject*, PyObject* args, PyObject* kwds) {
static const char* const_kwlist[] = {"image", "p1", "p2", "color", 0};
static char** kwlist = const_cast<char**>(const_kwlist);
PyBlitzArrayObject* image = 0;
Py_ssize_t y1, x1, y2, x2;
PyObject* color = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&(nn)(nn)O", kwlist,
&PyBlitzArray_OutputConverter, &image,
&y1, &x1, &y2, &x2, &color)) return 0;
//protects acquired resources through this scope
auto image_ = make_safe(image);
switch(image->type_num) {
case NPY_UINT8:
return inner_line<uint8_t>(image, y1, x1, y2, x2, color);
case NPY_UINT16:
return inner_line<uint16_t>(image, y1, x1, y2, x2, color);
case NPY_FLOAT64:
return inner_line<double>(image, y1, x1, y2, x2, color);
default:
PyErr_Format(PyExc_TypeError, "drawing operation does not support images with data type `%s' (choose from uint8|uint16|float64)", PyBlitzArray_TypenumAsString(image->type_num));
}
return 0;
}
......@@ -33,9 +33,9 @@ static xbob::extension::FunctionDoc s_point = xbob::extension::FunctionDoc(
"the color planes: ``(3, height, width)``. Images are modified in place.\n"
)
.add_prototype("image, y, x, color")
.add_prototype("image, p, color")
.add_parameter("image", "array (uint8|uint16|float64, 3D)", "Input array containing an image with the shape ``(height, width)`` (for gray-scale images) or ``(3, height, width)`` (for color images)")
.add_parameter("y, x", "int", "Index (0-based) pointing to the location on the image that the pixel is going to be drawn.")
.add_parameter("p", "tuple", "a point, on the format ``(y, x)``, defining the location on the image that the pixel is going to be drawn.")
.add_parameter("color", "scalar|tuple", "Color of the pixel. In case the input image is gray-scale (2D), this should be a single scalar. If the input image is colored (3D), then it should be a sequence containing 3 scalars, representing the levels of red, green and blue (in this order) of the pixel to be drawn.")
;
......@@ -51,14 +51,45 @@ static xbob::extension::FunctionDoc s_try_point = xbob::extension::FunctionDoc(
":py:func:`point`, in this module. See its help message for details."
)
.add_prototype("image, y, x, color")
.add_prototype("image, p, color")
.add_parameter("image", "array (uint8|uint16|float64, 3D)", "Input array containing an image with the shape ``(height, width)`` (for gray-scale images) or ``(3, height, width)`` (for color images)")
.add_parameter("y, x", "int", "Index (0-based) pointing to the location on the image that the pixel is going to be drawn.")
.add_parameter("p", "tuple", "a point, on the format ``(y, x)``, defining the location on the image that the pixel is going to be drawn.")
.add_parameter("color", "scalar|tuple", "Color of the pixel. In case the input image is gray-scale (2D), this should be a single scalar. If the input image is colored (3D), then it should be a sequence containing 3 scalars, representing the levels of red, green and blue (in this order) of the pixel to be drawn.")
;
extern PyObject* PyBobIpDraw_Line(PyObject*, PyObject* args, PyObject* kwds);
static xbob::extension::FunctionDoc s_line = xbob::extension::FunctionDoc(
"line",
"Draws a line between two points on the given image.",
"This function is based on the Bresenham's line algorithm and is highly "
"optimized to be able to draw lines very quickly. There is no floating "
"point arithmetic nor multiplications and divisions involved. Only "
"additions, subtractions and bit shifting operations are used.\n"
"\n"
"The line may go out of the image bounds in which case such points "
"(lying outside the image boundary) are ignored.\n"
"\n"
"See also: http://en.wikipedia.org/wiki/Bresenham's_line_algorithm.\n"
"\n"
"This function can work with either gray-scale or color images. "
"In case you pass a 2D array representing a gray-scale image, this function "
"expects you pass a single scalar as a value for the input parameter "
"``color``. In the case you pass a 3D array (color image), then the color "
"parameter should be set to a tuple contanining 3 scalars representing the "
"levels for each of the color components (red, green and blue)\n"
"\n"
)
.add_prototype("image, p1, p2, color")
.add_parameter("image", "array (uint8|uint16|float64, 3D)", "Input array containing an image with the shape ``(height, width)`` (for gray-scale images) or ``(3, height, width)`` (for color images)")
.add_parameter("p", "tuple", "Points, on the format ``(y, x)``, defining the start and end of the line. Portions of the line outside the image range will be ignored.")
.add_parameter("color", "scalar|tuple", "Color of the pixel. In case the input image is gray-scale (2D), this should be a single scalar. If the input image is colored (3D), then it should be a sequence containing 3 scalars, representing the levels of red, green and blue (in this order) of the pixel to be drawn.")
;
/**
def("draw_line", &draw_line, (arg("image"), arg("y1"), arg("x1"), arg("y2"), arg("x2"), arg("color")), "Draws a line between two points p1(x1,y1) and p2(x2,y2). This function is based on the Bresenham's line algorithm and is highly optimized to be able to draw lines very quickly. There is no floating point arithmetic nor multiplications and divisions involved. Only addition, subtraction and bit shifting are used.\n\nThe line may go out of the image bounds in which case such points (lying outside the image boundary are ignored).\n\nReferences: http://en.wikipedia.org/wiki/Bresenham's_line_algorithm. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_cross", &draw_cross, (arg("image"), arg("y"), arg("x"), arg("radius"), arg("color")), "Draws a cross with a given radius and color at the image. Uses the draw_line() primitive above. The cross will look like an 'x' and not like a '+'. To get a '+' sign, use the draw_cross_plus() variant. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_cross_plus", &draw_cross_plus, (arg("image"), arg("y"), arg("x"), arg("radius"), arg("color")), "Draws a cross with a given radius and color at the image. Uses the draw_line() primitive above. The cross will look like an '+' and not like a 'x'. To get a 'x' sign, use the draw_cross() variant. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
def("draw_box", &draw_box, (arg("image"), arg("y"), arg("x"), arg("height"), arg("width"), arg("color")), "Draws a box at the image using the draw_line() primitive. This method supports both grayscale (2D) or color RGB (3D) images. Depending on your image type, select an appropriate color value: a single gray value for 2D grayscale images or a 3-tuple containing the RGB color to set during drawing.");
......@@ -77,6 +108,12 @@ static PyMethodDef module_methods[] = {
METH_VARARGS|METH_KEYWORDS,
s_try_point.doc()
},
{
s_line.name(),
(PyCFunction)PyBobIpDraw_Line,
METH_VARARGS|METH_KEYWORDS,
s_line.doc()
},
{0} /* Sentinel */
};
......
......@@ -7,25 +7,25 @@
* Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
*/
#include <xbob.blitz/cppapi.h>
#include <xbob.blitz/cleanup.h>
#include <boost/tuple/tuple.hpp>
#include <bob/ip/drawing.h>
#include "utils.h"
template <typename T>
static PyObject* inner_point (PyBlitzArrayObject* image,
int y, int x, PyObject* color) {
Py_ssize_t y, Py_ssize_t x, PyObject* color) {
switch (image->ndim) {
case 2:
{
if (!PyArray_CheckScalar(color) && !PyNumber_Check(color)) {
PyErr_Format(PyExc_TypeError, "drawing on a 2D image (gray-scale) requires a color which is a scalar, not `%s'", Py_TYPE(color)->tp_name);
return 0;
}
T c = PyBlitzArrayCxx_AsCScalar<T>(color);
if (PyErr_Occurred()) return 0;
T c;
int ok = get_color1(color, c);
if (!ok) return 0;
try {
bob::ip::draw_point(*PyBlitzArrayCxx_AsBlitz<T,2>(image), y, x, c);
......@@ -38,25 +38,18 @@ static PyObject* inner_point (PyBlitzArrayObject* image,
PyErr_SetString(PyExc_RuntimeError, "caught unknown exception while calling C++ bob::ip::draw_point");
return 0;
}
}
break;
case 3:
{
if (!PySequence_Check(color) || (PySequence_Fast_GET_SIZE(color) != 3)) {
PyErr_Format(PyExc_TypeError, "drawing on a 3D image (colored) requires a color which is a sequence (tuple, list, etc) with 3 components");
return 0;
}
boost::tuple<T,T,T> c(
PyBlitzArrayCxx_AsCScalar<T>(PyTuple_GET_ITEM(color, 0)),
PyBlitzArrayCxx_AsCScalar<T>(PyTuple_GET_ITEM(color, 1)),
PyBlitzArrayCxx_AsCScalar<T>(PyTuple_GET_ITEM(color, 2))
);
if (PyErr_Occurred()) return 0;
T r, g, b;
int ok = get_color3(color, r, g, b);
if (!ok) return 0;
try {
bob::ip::draw_point(*PyBlitzArrayCxx_AsBlitz<T,3>(image), y, x, c);
bob::ip::draw_point(*PyBlitzArrayCxx_AsBlitz<T,3>(image), y, x,
boost::tuple<T,T,T>(r, g, b));
}
catch (std::exception& e) {
PyErr_Format(PyExc_RuntimeError, "%s", e.what());
......@@ -82,16 +75,16 @@ static PyObject* inner_point (PyBlitzArrayObject* image,
PyObject* PyBobIpDraw_Point (PyObject*, PyObject* args, PyObject* kwds) {
static const char* const_kwlist[] = {"image", "y", "x", "color", 0};
static const char* const_kwlist[] = {"image", "p", "color", 0};
static char** kwlist = const_cast<char**>(const_kwlist);
PyBlitzArrayObject* image = 0;
Py_ssize_t x = 0;
Py_ssize_t y = 0;
Py_ssize_t x = 0;
PyObject* color = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&nnO", kwlist,
&PyBlitzArray_OutputConverter, &image, &x, &y, &color)) return 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&(nn)O", kwlist,
&PyBlitzArray_OutputConverter, &image, &y, &x, &color)) return 0;
//protects acquired resources through this scope
auto image_ = make_safe(image);
......
......@@ -11,7 +11,7 @@
import numpy
import nose.tools
from . import point, try_point#, line, box
from . import point, try_point, line#, box
def test_gray_point():
......@@ -20,7 +20,7 @@ def test_gray_point():
image.fill(0)
# Draws a white point on the middle
point(image, 50, 50, 255)
point(image, (50, 50), 255)
nose.tools.eq_(image[50, 50], 255)
def test_does_not_raise_gray():
......@@ -28,14 +28,14 @@ def test_does_not_raise_gray():
image = numpy.ndarray((100, 100), 'uint8')
image.fill(0)
imcopy = image.copy()
try_point(imcopy, 100, 100, 255)
try_point(imcopy, (100, 100), 255)
assert numpy.array_equal(image, imcopy) # no change is made
@nose.tools.raises(RuntimeError)
def test_raises_gray():
image = numpy.ndarray((100, 100), 'uint8')
point(image, 100, 100, 255)
point(image, (100, 100), 255)
def test_color_point():
......@@ -49,7 +49,7 @@ def test_color_point():
image.fill(0)
# Draws a white point on the middle
point(image, 50, 50, white)
point(image, (50, 50), white)
assert numpy.array_equal(image[:,50, 50],a1)