pythonnumpyopencvvips

how to rotate and pad huge numpy arrays without consuming too much memory?


I'm working with big wsi images, while making wsi I'm using opencv for calculations and appending frames into a huge numpy array(50kx50kx3 array taking 7.5gb memory), for saving I was using opencv imwrite function but when I was trying to open those saved tiff files with openslide it throws "unsupported or missing image file" error.

I found out opencv doesn't save images as pyramids, then I tried to save images as pyramids using pyvips, before save I need to rotate image because camera is rotated for faster scanning, but when I do rotate with opencv it doubles amount of memory consumed by program, I wonder if there is another method to rotate without huge memory usage, this also happens when I reach edges of image and therefore need to pad it to not overflow, but it goes down after doing pad and just takes double memory at first, is there optimal method to do the pad and rotate? here's where I pad array:

if np.shape(test_matrix)[1] - (cm2 + int(y_edge_on_wsi) + y_in) <= 2000:
    test_matrix = np.pad(test_matrix, ((0, 0), (0, 10000), (0, 0)), mode='constant', constant_values=255)
                

if np.shape(test_matrix)[0] - (cm1 + int(x_edge_on_wsi) + x_in) <= 2000:
                        test_matrix = np.pad(test_matrix, ((0, 10000), (0, 0), (0, 0)), mode='constant', constant_values=255)
                

# Add rows or columns to The beginning of the test_matrix
if cm2 + int(y_edge_on_wsi) <= 2000:
    test_matrix = np.pad(test_matrix, ((0, 0), (10000, 0), (0, 0)), mode='constant', constant_values=255)
    cm2 = cm2 + 10000
if cm1 + int(x_edge_on_wsi) <= 2000:
    test_matrix = np.pad(test_matrix, ((10000, 0), (0, 0), (0, 0)), mode='constant', constant_values=255)
    cm1 = cm1 + 10000

and here's where I do rotate before saving image:

self.image = cv2.rotate(self.image, cv2.ROTATE_90_CLOCKWISE)
cv2.imwrite(self.fullSavePathTiff, self.image)

here's memory usage before rotate: memory usage before rotate

and this is memory usage after rotate: memory usage after rotate


Solution

  • You can do the rotate in pyvips, perhaps:

    image = pyvips.Image.new_from_array(numpy_array)
    image.rot90().write_to_file("xxx.tif",
        pyramid=True,
        tile=True,
        compression="jpeg",
        Q=85)
    

    pyvips will do the rotate and the save directly from the memory on your numpy array, so there will only be a small amount of extra RAM used. It should be quick too.