Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Use pybind11 in image module #26275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 27, 2023
Merged

Conversation

ianthomas23
Copy link
Member

Closes the fourth item of issue #23846.

This changes the image module to use pybind11 rather than our array_view classes and direct use of the Python/C API. On my Linux dev machine this brings the _image*.so library down from 1.8 MB to 1.0 MB.

I've taken the usual approach of the minimal set of changes to switch to pybind11. This means that in some places we are still passing around pointers to array buffers an integer array dimensions. We could consider improving that in future, but it might be better to leave it as it is using the "if it ain't broke" principle.

The standard approach to using pybind11 is to use the py namespace, i.e.

namespace py = pybind11;

but I haven't done this as we already have a py namespace in py_adapters.h and we can't keep both separate as importing some of the agg header files, as needed here, inevitably pulls in py_adapters.h. When we have completed the transition to pybind11 we can change this.

There are a number of utility functions in py_converters.h and .cpp which use PyObject and void pointers. I have started a pybind11 equivalent of this in py_converters_11.h and .cpp, and again when the pybind11 transition is completed we can delete the old ones.

With regard to code formatting, I have just done what I would do instinctively without thinking about it much and I am very happy to make changes if anyone has a strong opinion.

(type == NPY_INT16) ? resample<agg::gray16> :
(type == NPY_FLOAT32) ? resample<agg::gray32> :
(type == NPY_FLOAT64) ? resample<agg::gray64> :
(dtype.is(pybind11::dtype::of<std::uint8_t>())) ? resample<agg::gray8> :
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more verbose than it used to be, but is the recommended way of checking dtypes in pybind11.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At SciPy Conf 2023, I asked Henry (pybind11 maintainer) if there was a less verbose way to do this type of check and he said this was the best way.

@ianthomas23 ianthomas23 force-pushed the pybind11_image2 branch 2 times, most recently from 22a0788 to ce7afe1 Compare July 8, 2023 14:50
@oscargus oscargus added this to the v3.8.0 milestone Jul 13, 2023
@oscargus
Copy link
Member

I cannot really review it properly, but I am positive to the effort! Are the failing tests somehow related? It seems like they may be, but then they only show up for some Python versions...

@ianthomas23
Copy link
Member Author

The tests are related, but I am away from dev machine at SciPy this week. I'll return to this next week.

Copy link
Contributor

@thomasjpfan thomasjpfan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR looks like a fairly straight forward migration!

if (py_inverse == NULL) {
return NULL;
}
pybind11::ssize_t mesh_dims[2] = {dims[0]*dims[2], 2};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be dims[1]?

Suggested change
pybind11::ssize_t mesh_dims[2] = {dims[0]*dims[2], 2};
pybind11::ssize_t mesh_dims[2] = {dims[0]*dims[1], 2};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it should.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


if (params.interpolation < 0 || params.interpolation >= _n_interpolation) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this _n_interpolation check still required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good question. The value is only ever used internally (between the Python and C++ code) and there is no way for a user to get this value as it is not part of the _interpd_ str to enum mapping.

On reflection, I think the correct approach is to remove it completely from the enum.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

&params.alpha, &convert_bool, &params.norm, &params.radius)) {
return NULL;
}
if (ndim < 2 || ndim > 3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nit:

Suggested change
if (ndim < 2 || ndim > 3)
if (ndim != 2 || ndim != 3)

So it's easier to connect the error message with the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but it would need to be ndim != 2 && ndim != 3.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@thomasjpfan thomasjpfan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

(type == NPY_INT16) ? resample<agg::gray16> :
(type == NPY_FLOAT32) ? resample<agg::gray32> :
(type == NPY_FLOAT64) ? resample<agg::gray64> :
(dtype.is(pybind11::dtype::of<std::uint8_t>())) ? resample<agg::gray8> :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At SciPy Conf 2023, I asked Henry (pybind11 maintainer) if there was a less verbose way to do this type of check and he said this was the best way.

@ksunden ksunden modified the milestones: v3.8.0, v3.9.0 Aug 8, 2023
@oscargus oscargus mentioned this pull request Mar 30, 2023
13 tasks
@QuLogic
Copy link
Member

QuLogic commented Sep 14, 2023

It looks like pybind11 generates a function signature, so that could be removed from image_resample__doc__.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants