binvox-rw-py icon indicating copy to clipboard operation
binvox-rw-py copied to clipboard

The write function doesn't work with Python 3

Open Lswbanban opened this issue 4 years ago • 6 comments

If you open a file in binary 'wb' mode and call the write function you get some errors:

fp = open("test.binvox", "wb")
voxels.write(fp)

To fix the error, I have:

  1. called ".encode('ascii')" on all the header string lines
  2. called ".tobytes()" on the numpy bool state variable: state.tobytes()
  3. called ".to_bytes(1, byteorder='little')" on the ctr variable: ctr.to_bytes(1, byteorder='little')

Not sure if it is the best fix, but at least it worked for me.

Lswbanban avatar Mar 10 '20 06:03 Lswbanban

can you please share an example of your py file? I am having the same issue

bishoyroufael avatar Jun 25 '20 18:06 bishoyroufael

Sure, here is the modified function:

def write(voxel_model, fp):
    """ Write binary binvox format.

    Note that when saving a model in sparse (coordinate) format, it is first
    converted to dense format.

    Doesn't check if the model is 'sane'.

    """
    if voxel_model.data.ndim==2:
        # TODO avoid conversion to dense
        dense_voxel_data = sparse_to_dense(voxel_model.data, voxel_model.dims)
    else:
        dense_voxel_data = voxel_model.data

    fp.write('#binvox 1\n'.encode('ascii'))
    line = 'dim '+' '.join(map(str, voxel_model.dims))+'\n'
    fp.write(line.encode('ascii'))
    line = 'translate '+' '.join(map(str, voxel_model.translate))+'\n'
    fp.write(line.encode('ascii'))
    line = 'scale '+str(voxel_model.scale)+'\n'
    fp.write(line.encode('ascii'))
    fp.write('data\n'.encode('ascii'))
    if not voxel_model.axis_order in ('xzy', 'xyz'):
        raise ValueError('Unsupported voxel model axis order')

    if voxel_model.axis_order=='xzy':
        voxels_flat = dense_voxel_data.flatten()
    elif voxel_model.axis_order=='xyz':
        voxels_flat = np.transpose(dense_voxel_data, (0, 2, 1)).flatten()

    # keep a sort of state machine for writing run length encoding
    state = voxels_flat[0]
    ctr = 0
    for c in voxels_flat:
        if c==state:
            ctr += 1
            # if ctr hits max, dump
            if ctr==255:
                fp.write(state.tobytes())
                fp.write(ctr.to_bytes(1, byteorder='little'))
                ctr = 0
        else:
            # if switch state, dump
            if ctr > 0:
                fp.write(state.tobytes())
                fp.write(ctr.to_bytes(1, byteorder='little'))
            state = c
            ctr = 1
    # flush out remainders
    if ctr > 0:
        fp.write(state.tobytes())
        fp.write(ctr.to_bytes(1, byteorder='little'))

Lswbanban avatar Jun 30 '20 04:06 Lswbanban

I faced the same problem,so that I gave up this package last year. Is there any idea to fix it? I had to change it into ndarray with NumPy to edit binvox file.

tianyilt avatar Jan 02 '21 11:01 tianyilt

@tianyilt I just gave the fix in the comment above. Just replace the function, and it should work.

Lswbanban avatar Jan 02 '21 12:01 Lswbanban

Thankes. @Lswbanban

tianyilt avatar Jan 02 '21 12:01 tianyilt

It would be great if this edit can be included as an official change at some point since most people use Python3 now.

Thanks @Lswbanban for sharing the mod!

@dimatura

josephko91 avatar Sep 26 '23 15:09 josephko91