Forum

Author Topic: uugghhh adding a single camera and mask  (Read 6023 times)

kBarra

  • Newbie
  • *
  • Posts: 9
    • View Profile
uugghhh adding a single camera and mask
« on: July 15, 2015, 10:34:22 AM »
I have been using photoscan 0.9 api up until now. I am finally making my way in to the upgraded, feature removed, api 1.0+. And boy oh boy is it painful, convoluted, and stripped of information.

Where do I even start? Adding photos I suppose... I do not want to use the command .addPhotos(). I want to add a single photo, get the object returned, do some stuff like label changing, and then add a mask. All I have been met with is frustration, and confusion. The docs have basically zero information...

why does this not work.

Code: [Select]
doc = PhotoScan.app.document
chunk = doc.chunks[0]
cam = chunk.addCamera()
cam.open( imagePath )
cam.label = "pleaseWork"

maskPhoto = PhotoScan.Mask()
maskPhoto.load( maskPath )

PhotoScan.utils.createDifferenceMask( cam.photo.image(), maskPhoto.image() , 12)


....


Why are things returning true or false, this information is useless, why have you switched to giving less information back to the user? Am I the only one complaining about this? Am I using this newer API just absolutely wrong? Why the convoluted, mask.load() but cam.open().... I apologize about bashing your code like this, but the previous implementation was leaps and bounds better, and more pythonic, in my opinion.
« Last Edit: July 15, 2015, 10:36:22 AM by kBarra »

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14847
    • View Profile
Re: uugghhh adding a single camera and mask
« Reply #1 on: July 15, 2015, 12:10:27 PM »
Hello kBarra,

Could you please describe the workflow in step by step basis?

In the code I can see several potential problems:
1) it's not clear, whether you have or not any chunks in the document, if there're no chunk, the second line will fail.
2) creating camera instances via addCamera() method intends to create also Sensor instance (in order to have proper calibration group in the Tools Menu -> Camera Calibration window. So I can suggest to use addPhotos() function and use the list of path as an argument, even if the list contain only single element.
3) When creating a different mask on input you need to give two PhotoScan.Images(), so there's no need to create a Mask instance, since you need just to load common Image. Also this operations returns an image as a result, so you should probably write it to the variable and then when creating Mask for the image, just use mask.setImage() method.

Best regards,
Alexey Pasumansky,
Agisoft LLC

kBarra

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: uugghhh adding a single camera and mask
« Reply #2 on: July 15, 2015, 08:25:33 PM »
1) Yes there is a chunk in my project.

2) I am trying to avoid having to use this code block after the addPhotos()
Code: [Select]
cam = chunk.cameras[-1]
as it is ugly, uninformative, unpythonic, and looks like it is prone to breaking.

3) so you are saying my code should look like
Code: [Select]
doc = PhotoScan.app.document
chunk = doc.chunks[0]
cam = chunk.addCamera()
cam.open( imagePath )
cam.label = "pleaseWork"

maskPhoto = PhotoScan.Images()
maskPhoto = maskPhoto.open( maskPath )

PhotoScan.utils.createDifferenceMask( cam.photo.image(), maskPhoto , 12)


There is zero information about setImage in the documentation http://www.agisoft.com/pdf/photoscan_python_api_1_1_0.pdf can you please be more specific about how to use this command?

kBarra

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: uugghhh adding a single camera and mask
« Reply #3 on: July 15, 2015, 10:30:15 PM »
Alexey, this is what I would like to avoid

Code: [Select]
chunk.addPhotos(["Volumes/PROJECTS/2015_0701_demoDay_mollyO/_AUTO/_output/FACE/no_camXML/t001/jpg/20150701_MAC2_internal_blendShapes_mollyO_Face_t001_2577.jpg"])
True

>>> chunk.cameras[-1]
<Camera '20150701_MAC2_internal_blendShapes_mollyO_Face_t001_2577.jpg'>

>>> chunk.addPhotos(["/Volumes/PROJECTS/2015_0701_demoDay_mollyO/_AUTO/_output/FACE/no_camXML/t001/jpg/20150701_MAC2_internal_blendShapes_mollyO_Face_t001_2480.jpg"])
True

>>> chunk.cameras[-1]
<Camera '20150701_MAC2_internal_blendShapes_mollyO_Face_t001_2577.jpg'>


chunk.cameras[-1] does not give me the last camera added, but the last camera in the alphabetized list that is returned by chunk.cameras[].


Yes, alphabetizing my list before i go into a loop and use addPhotos() with one image passed in is not hard, but it is trivial, harder to read, and not something that should have to be done.

Have you thought about adding an addPhoto() function that does the same as addPhotos() except it takes a filepath, not an array, and returns the camera-created/None, not True/False.



But I'm getting sidetracked, what is the workflow to add a single camera, attach a photo, set a mask, and create a difference mask in agisoft api 1.1+. After you outline this workflow can you please add it to your documentation for future users?
« Last Edit: July 15, 2015, 10:57:23 PM by kBarra »

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14847
    • View Profile
Re: uugghhh adding a single camera and mask
« Reply #4 on: July 16, 2015, 10:39:43 AM »
Hello kBarra,

chunk.cameras[-1] returns the last camera in the list of cameras, displayed in the Workspace pane.
Instead of [-1] index it is also possible to use (len(chunk.cameras) - 1) to access the last element in the list.

Here's a sample code that adds a photo using addCamera method, creates a calibration group and creates a difference mask:

Code: [Select]
import PhotoScan

doc = PhotoScan.app.document
chunk = doc.chunk

image_path = "D:\\image.jpg"
mask_path = "D:\\mask.png"

camera = chunk.addCamera() #loading photo to the camera instance
camera.label = image_path.rsplit("\\", 1)[1]
camera.open(image_path)

sensor = chunk.addSensor() #creating camera calibration group for the loaded image
sensor.label = "Calibration Group 1"
sensor.type = PhotoScan.Sensor.Type.Frame
sensor.width = camera.photo.image().width
sensor.height = camera.photo.image().height
camera.sensor = sensor

bg_image = PhotoScan.Image() #creating mask from background image using difference masking
bg_image = bg_image.open(mask_path)
mask_image = PhotoScan.utils.createDifferenceMask(camera.photo.image(), bg_image, 20)
mask = PhotoScan.Mask()
mask.setImage(mask_image)
camera.mask = mask
Best regards,
Alexey Pasumansky,
Agisoft LLC

kBarra

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: uugghhh adding a single camera and mask
« Reply #5 on: July 17, 2015, 04:17:32 AM »
dude, awesome! Literally no way I would have been able to figure this out. For the sensor label, is it fine for all sensors to have the same name? Is that a preferred method?

Just to make sure I understand the (len(chunk.cameras) - 1) . It should be used like so?
Code: [Select]
chunk.cameras[ (len(chunk.cameras) - 1)  ]

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14847
    • View Profile
Re: uugghhh adding a single camera and mask
« Reply #6 on: July 17, 2015, 08:24:58 AM »
Hello kBarra,

For sensors there's no problem to have the same label, but important thing is to use valid width and height.
In case you are using the same camera with the same focal length, you can assign the same sensor for all the cameras, it will mean that all cameras will be calibrated with the same settings.

len(chunk.cameras) gives you total number of cameras in the list, but since the first element has zero index, you need to subtract 1 to get the index of the last element.
Best regards,
Alexey Pasumansky,
Agisoft LLC