-
Notifications
You must be signed in to change notification settings - Fork 188
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
RFC: Reverse Array dims in no-copy conversion from Julia to Numpy #85
Conversation
The PyObject constructor tells Python the correct ordering of the dimensions; it sounds like you just don't like the behavior of matplotlib's |
I guess. Here's some more context: when I read a frame from a video, for example, I'll get a julia> using AV
julia> f = AV.open("/home/kevin/Videos/chunk_0.mp4")
AVCapture("/home/kevin/Videos/chunk_0.mp4", ...)
julia> img = read(f)
3x960x540 Array{Uint8,3}:
[:, :, 1] =
...
julia> PyPlot.imshow(img)
ERROR: PyError (PyObject_Call) <type 'exceptions.TypeError'>
TypeError('Invalid dimensions for image data',)
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 2892, in imshow
imlim=imlim, resample=resample, url=url, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/axes.py", line 7300, in imshow
im.set_data(X)
File "/usr/lib/pymodules/python2.7/matplotlib/image.py", line 429, in set_data
raise TypeError("Invalid dimensions for image data")
in pyerr_check at /home/kevin/.julia/v0.3/PyCall/src/exception.jl:58
in pycall at /home/kevin/.julia/v0.3/PyCall/src/PyCall.jl:85
in imshow at /home/kevin/.julia/v0.3/PyPlot/src/PyPlot.jl:250
julia> size(img)
(3,960,540)
julia> strides(img)
(1,3,2880) I find that reordered dimensions to So, one thought I had was to have a parameter to the Thoughts? Is there a better way to deal with this directly in |
I see. This seems one of those arbitrary limitations of matplotlib that I keep running into, and I usually try to work around it to make the Julia interface more flexible. I think it would be reasonable to write an But you're right that this looks like it would ideally require some support in PyCall: there should be a low-level variant of the |
I've updated this PR so that the function PyObject{T<:NPY_TYPES}(a::StridedArray{T}, revdims::Bool=false) Let me know if this works, or if you would prefer a different interface. I also just submitted JuliaPy/PyPlot.jl#73, which uses this constructor for That PR shouldn't be merged until this one is tagged. |
Well, I guess both could remain untagged as long as |
Hi @kmsquire, sorry I lost track of this. This looks good to merge given a rebase and a test. |
In some cases, an array is already in row-major order (e.g., RGB images) and it is useful to reverse the order of dimensions passed to PyArray_New. This PR updates the PyObject constructor for StridedArrays to optionally allow this.
Me too. ;-) Rebased. |
I'll add a test in a little while. |
@@ -175,14 +175,20 @@ const npy_typestrs = Dict( "b1"=>Bool, | |||
######################################################################### | |||
# no-copy conversion of Julia arrays to NumPy arrays. | |||
|
|||
function PyObject{T<:NPY_TYPES}(a::StridedArray{T}) | |||
# In some cases, an array is already in row-major order (e.g., RGB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say rather than "Julia arrays are in column-major order, but in some cases it is useful to pass them to Python as row-major arrays simply by reversing the dimensions. For example, although NumPy works with both row-major and column-major data, some Python libraries like OpenCV seem to require row-major data (the default in NumPy). In such cases, use PyObject(array, true)
."
And then add a similar comment to the README.md file.
Ping, any chance of a test? (The AppVeyor failure looks like an unrelated network problem.) |
Probably just something like if PyCall.npy_initialized
let A = rand(2,3,4), o = PyObject(A, true), A2 = convert(PyAny, o)
@test A == permutedims(A2, [3,2,1])
end
end |
# images) and it is useful to reverse the order of dimensions passed | ||
# to PyArray_New. In these cases, set revdims=true. | ||
|
||
function PyObject{T<:NPY_TYPES}(a::StridedArray{T}, revdims::Bool=false) | ||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not silently fall back on failure to array2py(a) if revdims=true. It produces inconsistent behavior. Is there some way array2py could take revdims as an extra arg as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. For now, it can throw an error if revdims=true
but in the future array2py
could implement this too.
Reproduction: https://gist.github.com/dmrd/b47c89c045279973258f997eeff1e863 Can we add BitArray--> Array{uint8} conversion as a default? Numpy doesn't seem to do bit arrays. |
@dmrd, a converter for |
In some cases, Python code expects a row-major array instead of Julia's native column-major order, or you have a Julia array that you want to interpret as row-major data. PyReverseDims(array) allows you to pass a Julia array as a NumPy row-major array with the dimensions in reversed order. Based on PR #85 by Kevin Squire.
Closing in favor of JuliaLang/julia#265 |
Thanks, @StevenG, and sorry not to be more responsive. |
No problem, thanks for doing most of the work on this! |
I've been working with image data and
PyPlot.imshow
, and finding that I have to munge the data more than I would like in order to get it to display:Digging into this, I found that reversing the dims and strides in the
PyObject
constructor let me display the image (more) directly withPyPlot.imshow(img.data)
.Now it's likely that this change would cause issues with other arrays being passed to Numpy, so I don't expect this to be merged. But I'm wondering if a version which reverses the dims/strides can be made available somehow?