Set Render/Camera resolution to Render Border coordinates
For perspective camera's you can use this. Original code from https://github.com/ChameleonScales/Camera-Cropper-Splitter just cleaned up a bit.

It uses the shift property of the camera to match the original camera image. For some cases this is useful, but other cases it ain't. Then you really need to move the camera.

scene = bpy.data.scenes['Scene']
render = scene.render
camera = scene.camera

orig_res_x = render.resolution_x
orig_res_y = render.resolution_y

border_width = render.border_max_x-render.border_min_x
border_height = render.border_max_y-render.border_min_y
border_left = render.border_max_x+render.border_min_x
border_top = render.border_max_y+render.border_min_y
border_res_x = orig_res_x*border_width
border_res_y = orig_res_y*border_height

# ▼ Focal length change ▼ 
if (orig_res_x&gt;orig_res_y):
    if border_res_x &gt; border_res_y:
        camera.data.lens /= border_width
    else:
        camera.data.lens *= orig_res_x/border_res_y
else:
    if border_res_x &gt; border_res_y:
        camera.data.lens *= orig_res_y/border_res_x
    else :
        camera.data.lens /= border_width

# ▼ Resolution change ▼ 
render.resolution_x = round(border_res_x)
render.resolution_y = round(border_res_y)

# ▼ Shift X ▼ 
if border_res_x&gt;border_res_y:
    camera.data.shift_x = (0.5 * (border_top - 1)) / border_width
else :
    camera.data.shift_x = (0.5 * border_res_x * (border_left - 1))/(border_res_y * border_width)

# ▼ Shift Y ▼ 
if border_res_x&gt;border_res_y:
    camera.data.shift_y = (0.5 * border_res_y * (border_left - 1))/(border_res_x * border_height)
else :
    camera.data.shift_y = (0.5 * (border_top - 1)) / border_height