Skip to content
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

sofima.warp.render.tiles raise cv2.error: OpenCV(4.7.0) (-215:Assertion failed) dst.cols < SHRT_MAX && dst.rows < SHRT_MAX && src.cols < SHRT_MAX && src.rows < SHRT_MAX in function 'remap' #49

Open
youssefmys opened this issue Nov 21, 2023 · 3 comments

Comments

@youssefmys
Copy link

youssefmys commented Nov 21, 2023

Following the stitching example for Sofima, the stitching is fine for small number of tiles, however I have 1631 EM tiles for stitching using the following tile_id_map

id_map = np.arange(1632).reshape(34, -1)
tile_id_map = id_map.copy() 
for i in range(id_map.shape[0]):
    if i % 2 == 1:
        tile_id_map[i, :] = tile_id_map[i, :][::-1]

Each tile is down sampled to about 5 MB


def read_image(image_path, x, y):
    f = open(image_path, 'rb')
    image_data = f.read()
    image = PIL.Image.open(io.BytesIO(image_data)).convert("L")
    image_np = np.array(image) 
    image.close()
    print(f"Read image {os.path.basename(image_path)}   \r", end=" ")
    return x, y, image_np 

with futures.ThreadPoolExecutor(max_workers=20) as executor:

    for y in range(tile_id_map.shape[0]):
        for x in range(tile_id_map.shape[1]):
            tile_id = tile_id_map[y, x]
                      
            image_path =  os.path.join(args.folder, f"down_sampled_Stitched_{tile_id:0>4}.tiff")
            f = executor.submit(read_image, image_path, x, y)
            future_to_tile_id.update({f: tile_id})


for f in futures.as_completed(future_to_tile_id):
    try:
        x, y, image_np = f.result()
        tile_map[(x, y)] = image_np
    except Exception as exc:
        print(f"Generated Execption: {exc}")

The rest of the stitching code is the same as Sofima stitching example using tile_space = (tile_id_map.shape[0],tile_id_map.shape[1]) and cx, cy = stitch_rigid.compute_coarse_offsets(tile_space, tile_map, ((1500, 500),(1500, 500)))

However, warp_subvolume raise error when trying to warp the tile using sofima.warp.render.tiles .
opencv version is 4.7

File "/home/youssef/workspace/sofima_trials/./stitchsupertiles.py", line 289, in <module>
    # Warp the tiles into a single image.
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/site-packages/sofima/warp.py", line 517, in render_tiles
    _render_tile(tile_x=x, tile_y=y, coord_map=coord_map)
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/site-packages/sofima/warp.py", line 465, in _render_tile
    warped_img, warped_mask = warp_subvolume(
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/site-packages/sofima/warp.py", line 182, in warp_subvolume
    f.result()
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/concurrent/futures/_base.py", line 451, in result
    return self.__get_result()
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/concurrent/futures/_base.py", line 403, in __get_result
    raise self._exception
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/youssef/anaconda3/envs/sofima/lib/python3.10/site-packages/sofima/warp.py", line 169, in _warp_section
    warped[c, z, ...] = cvx2.remap(
cv2.error: OpenCV(4.7.0) /home/conda/feedstock_root/build_artifacts/libopencv_1678824110780/work/modules/imgproc/src/imgwarp.cpp:1724: error: (-215:Assertion failed) dst.cols < SHRT_MAX && dst.rows < SHRT_MAX && src.cols < SHRT_MAX && src.rows < SHRT_MAX in function 'remap'

There are several issues concerning opencv remap() dealing with large images. I am not sure if further down sampling of tiles would solve the issue and whether it is possible to pickle the result tile meshes for down sampled tiles and re-apply for large images.
Thanks in advance.

@arentkievits
Copy link

arentkievits commented Feb 2, 2024

OpenCV version 4.9.0.80

I'm also experiencing this issue, with 3D alignment of a single large volume of 54 sections, i.e.

data_2_warp.shape
(34039, 28719, 54, 1)

I'm warping section for section:

warped = [np.transpose(data_2_warp[:, :, 0:1, 0], [2, 1, 0])]

for z in tqdm(range(1, data_2_warp.shape[2])):
  data_box = bounding_box.BoundingBox(start=(0, 0, 0), size=(data_2_warp.shape[0], data_2_warp.shape[1], 1))
  out_box = bounding_box.BoundingBox(start=(0, 0, 0), size=(data_2_warp.shape[0], data_2_warp.shape[1], 1))

  data = np.transpose(data_2_warp[data_box.start[0]:data_box.end[0],
                                  data_box.start[1]:data_box.end[1],
                                  z:z+1, 0:1], [3, 2, 1, 0])
  warped.append(
      warp.warp_subvolume(data, data_box, inv_map_full[:, z:z+1, ...], box_high, stride, out_box, 'lanczos', parallelism=1)[0, ...])

Warping a subvolume (e.g. 2000x2000x54) of this array works fine and the result is as expected. But applying the warping to the full data_2_warp array gives the exact same error after about 5 minutes, for the first iteration of the loop:

---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
Cell In[155], line 11
      5 out_box = bounding_box.BoundingBox(start=(0, 0, 0), size=(data_2_warp.shape[0], data_2_warp.shape[1], 1))
      7 data = np.transpose(data_2_warp[data_box.start[0]:data_box.end[0],
      8                                 data_box.start[1]:data_box.end[1],
      9                                 z:z+1, 0:1], [3, 2, 1, 0])
     10 warped.append(
---> 11     warp.warp_subvolume(data, data_box, inv_map_full[:, z:z+1, ...], box_high, stride, out_box, 'lanczos', parallelism=1)[0, ...])

File ~/miniconda3/envs/sofima/lib/python3.9/site-packages/sofima/warp.py:176, in warp_subvolume(image, image_box, coord_map, map_box, stride, out_box, interpolation, offset, parallelism)
    173     fs.add(exc.submit(_warp_section, z=z))
    175   for f in futures.as_completed(fs):
--> 176     f.result()
    178 # Map IDs back to the original space, which might be beyond the range of
    179 # int32.
    180 if orig_to_low is not None:

File ~/miniconda3/envs/sofima/lib/python3.9/concurrent/futures/_base.py:439, in Future.result(self, timeout)
    437     raise CancelledError()
    438 elif self._state == FINISHED:
--> 439     return self.__get_result()
    441 self._condition.wait(timeout)
    443 if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:

File ~/miniconda3/envs/sofima/lib/python3.9/concurrent/futures/_base.py:391, in Future.__get_result(self)
    389 if self._exception:
    390     try:
--> 391         raise self._exception
    392     finally:
    393         # Break a reference cycle with the exception in self._exception
    394         self = None

File ~/miniconda3/envs/sofima/lib/python3.9/concurrent/futures/thread.py:58, in _WorkItem.run(self)
     55     return
     57 try:
---> 58     result = self.fn(*self.args, **self.kwargs)
     59 except BaseException as exc:
     60     self.future.set_exception(exc)

File ~/miniconda3/envs/sofima/lib/python3.9/site-packages/sofima/warp.py:163, in warp_subvolume.<locals>._warp_section(z)
    155 dx, dy = cv.convertMaps(
    156     dx,
    157     dy,
    158     dstmap1type=maptype,
    159     nninterpolation=(interpolation == cv.INTER_NEAREST),
    160 )
    162 for c in range(0, image.shape[0]):
--> 163   warped[c, z, ...] = cv.remap(
    164       image[c, z, ...], dx, dy, interpolation=interpolation
    165   )

error: OpenCV(4.9.0) /io/opencv/modules/imgproc/src/imgwarp.cpp:1744: error: (-215:Assertion failed) dst.cols < SHRT_MAX && dst.rows < SHRT_MAX && src.cols < SHRT_MAX && src.rows < SHRT_MAX in function 'remap'

Would a workaround be to use the distributed mesh optimization? Unfortunately I am running into some other error there.

@arentkievits
Copy link

arentkievits commented Feb 2, 2024

After doing some Googling, I found the following on the openCV forum: https://forum.opencv.org/t/about-shrt-max-in-function-cv-remap/2884

It appears that imwarp.cpp uses (short) integer arithmetics for performance reasons, so the image cannot be larger than 0x7fff (32767 pixels). It seems that this is an unchangeable parameter.

I tried cropping the x dimension of my data array to 32767-1 before warping (setting it to 32767 still made it fail), since all other dimensions are within the limit.

When doing this, it doesn't throw the error on my side. So it seems that there is a hard limit of 32766 pixels on each dimension of your image array.

@mjanusz
Copy link
Collaborator

mjanusz commented Feb 5, 2024

The best workaround here is likely to simply work with smaller image fragments, even if the sections themselves are very large. Mesh and flow processing can still be done as usual, but the rendering of the warped data should be done tile-wise (with user-defined tiles -- something like 1k^2 or 2k^2 pixels would be typical). In the em_alignment notebook, rendering is done section-wise, but warp.warp_subvolume can process arbitrary bounding boxes.

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

No branches or pull requests

3 participants