How to move objects via script so that they stay in camera view
camera.data.angle_x/y doesn't seem to follow changes in resolution, so I made the following script taking into account resolution, pixel aspect and focal length.&lt;
br&gt;
The following functions camera_normalized_frame1() and camera_normalized_frame2  both return camera frame normalized by the distance btween camera image plane and origin.
import bpy
from mathutils import Matrix

#-------------------------------------------------------------
def camera_normalized_frame1(cam):
    render = bpy.context.scene.render
    aspect = (render.resolution_x * render.pixel_aspect_x) \
                / (render.resolution_y * render.pixel_aspect_y)
    view_frame = cam.data.view_frame()
    frame = [-f/view_frame[0].z for f in view_frame]
    if aspect &gt; 1:
        mat = Matrix.Diagonal((1, 1/aspect, 1),)
    else:
        mat = Matrix.Diagonal((aspect, 1, 1), )
    for i in range(len(frame)):
        frame[i] = mat @ frame[i]
    return frame


#-------------------------------------------------------------
def camera_normalized_frame2(cam):

    import bpy_extras
    scene = bpy.context.scene

    frame = cam.data.view_frame()
    poss = bpy_extras.object_utils.world_to_camera_view(scene, cam, cam.matrix_world @ frame[0])

    ratio = [0.5/(poss[i]-0.5) for i in range(2)]
    norm_frame = []
    for f in frame:
        norm_frame.append(f.copy())
        for i in range(2):
            norm_frame[-1][i] *= ratio[i]
        norm_frame[-1] /= -norm_frame[-1][2]

    return norm_frame



Create Icosphere objects in the corners of a rendering imag.
import bpy
from mathutils import Matrix

cam = bpy.data.objects['Camera']
frame = camera_normalized_frame1(cam)
#frame = camera_normalized_frame2(cam)

distance = -cam.data.view_frame()[0].z
for v in frame:
    loc_l = distance * v
    loc_w = cam.matrix_world @ loc_l
    bpy.ops.mesh.primitive_ico_sphere_add(radius=0.1, location=loc_w)


Place objects at random locations within camera view.
import bpy
from mathutils import Vector, Matrix
import random, os
import math

random.seed(os.times().user)
min_z, max_z = 2, 10

# Base object for duplication
bpy.ops.mesh.primitive_ico_sphere_add(radius=0.05)
obj = bpy.context.object


cam = bpy.data.objects['Camera']
frame = camera_normalized_frame1(cam)
#frame = camera_normalized_frame2(cam)

for i in range(200):
    v = Vector([
                random.uniform(-1, 1) * frame[0].x, 
                random.uniform(-1, 1) * frame[0].y, 
                frame[0].z
                ])
    distance = max_z * math.sqrt(random.uniform( math.pow(min_z/max_z, 1), 1 ) )
    loc_w = cam.matrix_world @ (distance * v)

    obj.select_set(True)
    bpy.ops.object.duplicate_move_linked(TRANSFORM_OT_translate={&quot;value&quot;:loc_w})
    bpy.ops.object.select_all(action='DESELECT')

obj.hide_set(True)
bpy.context.view_layer.objects.active = cam