Preserving aspect ratio when running perspective correction

I have a workflow which detects an outline of a tray in a photo, then does a dynamic zone, then does a perspective correction to warp it to remove the perspective from the photo. This works fine, however the width and height in the perspective correction block are static, but I need them to be based on the dynamic zone output so that the aspect ratio of the tray is preserved. Is there a way to compute the width and height of the output from the dynamic zone block and use this as the width and height in the perspective correction block? Thanks.

Hey! I think I get what you are going for, but if not feel free to clarify. And in full disclosure, I just used the Roboflow Agent to build out this workflow, but it looks like I would have expected.

Basically added a Custom Python Block to capture the dimensions from the Dynamic Zone Block. Then put those captured variables into the Perspective Correction block.

Whole workflow looks like this:

Here’s the config for the Python block:

And here’s the Python code:

def run(self, zones):
if zones is None or len(zones) == 0:
return {"width": 0, "height": 0}

valid_polygons = []
for polygon in zones:
    try:
        points = np.asarray(polygon, dtype=np.float64).reshape(-1, 2)
    except (TypeError, ValueError):
        continue
    if len(points) >= 3:
        valid_polygons.append(points)

if len(valid_polygons) == 0:
    return {"width": 0, "height": 0}

polygon = max(valid_polygons, key=lambda p: abs(float(cv2.contourArea(p.astype(np.float32)))))
width = int(round(float(np.max(polygon[:, 0]) - np.min(polygon[:, 0]))))
height = int(round(float(np.max(polygon[:, 1]) - np.min(polygon[:, 1]))))
return {"width": max(0, width), "height": max(0, height)}

And here’s the inside of the Perspective Correction Block:

Let me know if you have questions!

Thanks for your reply. However, we tried using a custom Python block in Roboflow previously to solve a different issue and they come with a big issue: you cannot run them in a serverless which means running the workflows cost a LOT more. So that pretty much rules out using custom python blocks for us. I was hoping there may be some built in block in Roboflow that does this, but I guess if not, I will just need to perform the perspective correction in my own code outside of Roboflow - effectively ending the workflow at the dynamic zone block. Thanks anyway!

I know what you mean. In that case, have you tried Property Definition like below? Maybe that would work for your use-case.

Thanks for your reply. However, we tried using a custom Python block in Roboflow previously to solve a different issue and they come with a big issue: you cannot run them in a serverless

Good news, as of last August we support running Custom Python blocks on Serverless!

Thanks. I tried that but kept getting an error about the width and height not being integers which I could not work out how to fix… Do you know how?

Hopefully I have a fix for you. Here’s what the internal of my Property Definition block looks like. You might just be missing that final operation going to INT via “Convert to Number”.

Thanks. I appreciate you taking the time to reply again, but I tried this and spent a while trying different things but could not get it to work without errors.

To be honest, I feel like the Perspective Correction block should preserve the aspect ratio of the input by default, without requiring jumping through these hoops. Maybe it will in a future Roboflow update. But for now, I’m doing the perspective correction warp in my own code outside of Roboflow, which is working well for me.

YW. Wish we could have found the issue. Good point - it’s a Feature Request they might add to the list!