Forum

Author Topic: Create a buffer shape mask around a marker to cut off and save an image/camera.  (Read 1734 times)

Emanuele1234

  • Newbie
  • *
  • Posts: 14
    • View Profile
Hi everyone,

I return here, to ask a second question for my project. In fact now, I have a working algorithm that give me a list of best image for each 3d mark convert in 2d coordination. You can see the script below. Now ne problem is if it's possible sing the camera that I found with the algorithm to cut off for each camera of interest a piece of the best image. For do this I need to use My 2d coordinate for each mark, and create a buffer shape mask to use for cut off the selected image.

My working script for now it's this:

Code: [Select]
import Metashape
import csv


path = "I:/Backsjon190527/save_progress/"
doc = Metashape.Document()
doc.open(path + "Finale.psx")
chunk = doc.chunk
crs = chunk.crs
T = chunk.transform.matrix
print(crs)


csvfile = 'I:/Backsjon190527/save_progress/hs1.csv'
def ReadCSVasList(csvfile):
    try:
        with open(csvfile) as csv_file:
            reader = csv.reader(csv_file, dialect='excel')
            datalist = []
            datalist = list(reader)
            return datalist
    except IOError as err:
            print("I/O error({0})".format(err))


csv_data_list = ReadCSVasList(csvfile)
print(csv_data_list)
# To Ignore 1st Element (Headers)
csv_data_list.pop(0)
print(csv_data_list)

result = []

for x in csv_data_list:
        x.pop(0)
print(csv_data_list)

for i in range(0, len(csv_data_list), 1):
   result.append(list(map(float, csv_data_list[i])))

print(result)

selcam = list()

for x in result:
    ## script to find the best image near each marker in the Vector list.
    P = Metashape.Vector(x)  # point of interest in geographic coord
    mindis = 1e09
    # P = Metashape.Vector((459307.345426, 7192625.624622, 158.808)) # vector with X,Y,Z coordinates of point in same CRS as chunk ( I need to understand )
    cam_dist_P = {}  # dict containing  distance in pixels of P to each camera Principal Point

    for camera in chunk.cameras:
        sensor = camera.sensor
        w = sensor.width
        h = sensor.height
        cx = sensor.calibration.cx  # Principal point coordinates x
        cy = sensor.calibration.cy  # Principal point coordinates y
        if not camera.project(T.inv().mulp(chunk.crs.unproject(P))):  # check if projected Point within sensor size
            continue
        xp = camera.project(T.inv().mulp(chunk.crs.unproject(P))).x  # Prrojected point coordinates x
        yp = camera.project(T.inv().mulp(chunk.crs.unproject(P))).y  # Prrojected point coordinates y
        if xp < 0 or xp > w or yp < 0 or yp > h:  # check if projected PointI within sensor size
            continue
        dist = (camera.project(T.inv().mulp(chunk.crs.unproject(P))) - Metashape.Vector(
            (w / 2 + cx, h / 2 + cy))).norm()  # distance in pixels from projected point and P
        cam_dist_P[camera.label] = dist
        if dist < mindis:
            mindis = dist
            mincam = camera  # camera with min distance to Principal Point

    selcam.append(mincam)
        # for image in mincam:


        # Metashape.ModelKeyPoint(Metashape.PointCloud.renderImage(selcam), x)


    print(mincam)

    mincam.selected = True


print(selcam)


This script give to me this result:

[<Camera '100_0015_0047'>, <Camera '100_0015_0047'>, <Camera '100_0015_0048'>, <Camera '100_0015_0036'>, <Camera '100_0015_0036'>, <Camera '100_0015_0049'>, <Camera '100_0015_0048'>, <Camera '100_0015_0046'>, <Camera '100_0015_0046'>, <Camera '100_0015_0040'>, <Camera '100_0015_0047'>, <Camera '100_0015_0045'>, <Camera '100_0015_0040'>, <Camera '100_0015_0040'>, <Camera '100_0015_0046'>].

For the new problem I found on the metashape python reference manual some probably use full commands like these:


Code: [Select]
# c = Metashape.ImageCompression()
# c.jpeg_quality = 50
# chunk.cameras[mincam].image().save(path + fr"{test50}.jpg", c) #create a loop for new file names saving for each cutted image.
Metashape.Mask

# new_shape = chunk.shapes.addShape() #create a new mask shape to cut off a chunk of the selected photo.
# new_shape.type = Metashape.Shape.Polygon
# new_shape.has_z = False
# new_shape.center = [xxx] #center for the new shape?



Someone can give me some advice, or have any Idea to how continue this work?
Thank you in advance to who will help me!
Best regards,
Emanuele.

Paulo

  • Hero Member
  • *****
  • Posts: 1302
    • View Profile
Hello Emanuele,

the following script would loop over all markers in a project and find for each, the image where marker projection is closest to center and crop a 200 pixel by 200 pixel image centred on each marker.
Code: [Select]
import numpy
chunk = Metashape.app.document.chunk
T = chunk.transform.matrix
path = 'C:/Users/paul.pelletier/Downloads/FLIR_data/croppedImages/crop'   # path for export image crops
cam_xy_P = {}    # dict containing  (mincam, xp, yp, mindis) where xp yp are image coordinates of P in camera (mincam) with minimun distance (mindis) to Principal Point
selcam = list()
xcrop = 200 # cropsize x
ycrop = 200 # crop size y
num = 0
for m in chunk.markers:
mindis = 1e09

P = chunk.crs.project(T.mulp(m.position)) # vector with X,Y,Z coordinates of marker in chunk.crs

for camera in chunk.cameras:
sensor = camera.sensor
w = sensor.width
h = sensor.height
cx = sensor.calibration.cx  # Principal point coordinates x
cy = sensor.calibration.cy  # Principal point coordinates y
if not camera.project(T.inv().mulp(chunk.crs.unproject(P))): # check if projected Point exists
continue
xp = camera.project(T.inv().mulp(chunk.crs.unproject(P))).x  # Prrojected point coordinates x
yp = camera.project(T.inv().mulp(chunk.crs.unproject(P))).y  # Prrojected point coordinates y
if xp < 0 or xp > w or yp < 0 or yp > h: # check if projected PointI within sensor size
continue
dist = (camera.project(T.inv().mulp(chunk.crs.unproject(P)))-Metashape.Vector((w/2+cx,h/2+cy))).norm() # distance in pixels from projected point and PP
if dist < mindis :
mindis = dist
mincam = camera # camera with min distance to Principal Point

mincam.selected = True
cam_xy_P[num] = (mincam,mincam.project(T.inv().mulp(chunk.crs.unproject(P))).x,mincam.project(T.inv().mulp(chunk.crs.unproject(P))).y,mindis)
selcam.append(mincam)
img = mincam.image()
if img.data_type == 'U8':
ext ='.jpg'
dtype = numpy.uint8
if img.data_type == 'U16':
dtype = numpy.uint16
ext ='.tif'
if img.data_type == 'F32':
ext ='.tif'
dtype = numpy.float32
xmin = int(cam_xy_P[num][1]) - int(xcrop/2)
ymin = int(cam_xy_P[num][2]) - int(ycrop/2)
start = img.cn*(xmin+ymin*img.width)
arr = numpy.frombuffer(img.tostring(), dtype=dtype)
narr = numpy.array(([0] * xcrop * ycrop * img.cn),dtype=dtype)
for j in range(0,ycrop):
for i in range(0,xcrop*img.cn):
narr[i+j*xcrop*img.cn] = arr[start+i+j*img.width*img.cn]
cropimg  = Metashape.Image()
cropimg = cropimg.fromstring(narr.tobytes(),xcrop,ycrop,channels=img.channels,datatype=img.data_type)
cropimg.save(path+str(num)+ext)
num += 1

Metashape.app.photos_pane.setFilter(selcam)
Metashape.app.update()
print("Script finished!")

In example presented, there are 2 markers whose best projection falls on same image and the cropped images for each are shown to the right....

In your case you could replace for m in chunk.markers: with for x in result:
and P = chunk.crs.project(T.mulp(m.position)) with P = Metashape.Vector(x) supposing x contains coordinates (X,Y,Z) in same crs as chunk....

I hope you can adapt this script to your needs!,
« Last Edit: March 30, 2021, 07:39:10 AM by Paulo »
Best Regards,
Paul Pelletier,
Surveyor