Hello ramkunchur ,
sorry for the troubles, it turns out I was incorrect - rotating color frames is already available, the width of the (input) frame just has to be in multiples of 16. Here's a minimal example code.
Thanks, Erik

    Hi erik ,

    Thanks so much.

    I have come across another issue now, since I set preview to multiples of 16 i.e (640,400) originally it was (300,300)
    cam.setPreviewSize(300,300)
    changed to...
    cam.setPreviewSize(640,400)

    Inference doesn't work due to above changes, I tried to reset (300,300) to (640,400) in all other instances, inference doesn't work.

    Can you please tell me how I should adjust in other instances after changing preview size to 640,400?

    I also tried to change to (640,640) in all instances, get following error:

    [NeuralNetwork(2)] [warning] Input image (640x640) does not match NN (300x300)

    Need your help with this last step.

    Thanks & Best Regards,
    Ram

    • erik replied to this.

      Hello ramkunchur,
      here I quickly prepared a minimal solution to achieve that. It uses another ImageManip to crop the frame into 300x300. You could also use cropping on the first imageManip, but for some reason, the output frame doesn't keep its aspect ratio (it gets stretched).
      Thanks, Erik

        Hi erik
        Thanks so much for detailed help.
        The program doesn't seem to run... nothing happens

        Could you please check once?

        Thanks & Best Regards,
        Ram

        • erik replied to this.

          ramkunchur just tried it again; works as expected. I have depthai version 2.8 (in case you have an older version where it potentially doesn't work). What is the output of the program?
          Thanks, Erik

            Hi erik

            I am using Oak-1 and had depthai 2.1 installed

            I now installed depthai 2.8 ...

            I'm now getting rotated output without inference results.

            below is the error:
            [NeuralNetwork(4)] [warning] Input image (640x400) does not match NN (300x300)
            FPS:0.00

            Thanks & Best Regards,
            Ram

            • erik replied to this.

              Hi erik

              I will wait for your response...

              Requesting your help in this regard.

              Thanks & Best Regards,
              Ram

                ramkunchur

                It looks like you'll need to use ImageManip to crop and or "squeeze" the 640x400 resolution you have to the 300x300 resolution of the neural network.

                Thoughts?

                Thanks,
                Brandon

                  ramkunchur you are linking the incorrect imageManip output to the NN node. You should have linked the cropManip ImageManip node - that's the one that crops the 640x400 frames into 300x300 - to the NN input.
                  Thanks, Erik

                    Hi erik , Brandon

                    Thanks for your reply...

                    I've used same code from your example as below:

                    	camRgb = pipeline.createColorCamera()
                    	camRgb.setPreviewSize(640, 400)
                    	camRgb.setResolution(depthai.ColorCameraProperties.SensorResolution.THE_1080_P)
                    	camRgb.setInterleaved(False)
                    
                    	manipRgb = pipeline.createImageManip()
                    	rgbRr = depthai.RotatedRect()
                    	rgbRr.center.x, rgbRr.center.y = camRgb.getPreviewWidth() // 2, camRgb.getPreviewHeight() // 2
                    	rgbRr.size.width, rgbRr.size.height = camRgb.getPreviewHeight(), camRgb.getPreviewWidth()
                    	rgbRr.angle = 90
                    	manipRgb.initialConfig.setCropRotatedRect(rgbRr, False)
                    	camRgb.preview.link(manipRgb.inputImage)
                    
                    	cropManip = pipeline.createImageManip()
                    	cropManip.initialConfig.setResize(300, 300)
                    	manipRgb.out.link(cropManip.inputImage)
                    
                    	manipRgbOut = pipeline.createXLinkOut()
                    	manipRgbOut.setStreamName("cam_out")
                    	cropManip.out.link(manipRgbOut.input)

                    I still get same error as below:
                    [14442C1021FB92CD00] [140.524] [NeuralNetwork(4)] [warning] Input image (640x400) does not match NN (300x300)

                    I do get the output frame, however, without inference results...

                    Really need help to understand what I am doing wrong.
                    Alternatively, can you please provide an updated script of gen2-fatigue-detection with rotate option using the code suggested for rotate?

                    I am using this as an example... want to run inference with camera placed horizontally.

                    This is kind of important, thanks in advance for your time and help.

                    Thanks & Best Regards,
                    Ram

                    • erik replied to this.

                      ramkunchur yes, that's the correct code. I have created another demo code that links 300x300 rotated frames to mobilenet. You will need to place this script into depthai-python/examples, as it requires mobilenet blob. Unfortunately, I don't have time to update the script you mentioned, but I am sure you will be able to update it yourself with the help of the demo script I have just created - it should be straightforward.
                      Thanks, Erik

                        Hi erik ...

                        Thanks I'm able to get it right this time..

                        However, my full screen mode doesn't work with this, probably as it needs output resolution to be in multiples of 16...

                        Not sure how to resolve this as having full-screen output would have been nice

                        Thanks so much for your time and help... 🙂

                        Thanks & Best Regards,
                        Ram

                        • erik replied to this.

                          ramkunchur You could just use cv2.resize() function to upscale the 300x300 frame to the desired size. You could also stream 1080P video output to the device and display detections on the video frames - not 300x300 preview frame. So something similar to this example.
                          Thanks, Erik

                          a year later

                          Hello All,

                          I am trying to rotate my camera but I am confused by the links and syntax of this api and I need this done very soon for production. Here is my code:

                          def get_pipeline():
                              pipeline = dai.Pipeline()
                          
                              # # Define a source - color camera
                              cam = pipeline.createColorCamera()
                              cam.setBoardSocket(dai.CameraBoardSocket.RGB)
                              # cam.setInterleaved(False)
                              cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_48_MP)
                              cam.setVideoSize(1920, 1080)
                              cam.initialControl.setSceneMode(dai.CameraControl.SceneMode.FACE_PRIORITY)
                          
                              # Create MobileNet detection network
                              mobilenet = pipeline.create(dai.node.MobileNetDetectionNetwork)
                              mobilenet.setBlobPath(
                                  blobconverter.from_zoo(name="face-detection-retail-0004", shaves=3)
                              )
                              mobilenet.setConfidenceThreshold(0.7)
                          
                              crop_manip = pipeline.create(dai.node.ImageManip)
                              crop_manip.initialConfig.setResize(300, 300)
                              crop_manip.initialConfig.setFrameType(dai.ImgFrame.Type.BGR888p)
                              cam.isp.link(crop_manip.inputImage)
                              crop_manip.out.link(mobilenet.input)
                          
                              # Create an UVC (USB Video Class) output node. It needs 1920x1080, NV12 input
                              uvc = pipeline.createUVC()
                              cam.video.link(uvc.input)

                          This is what I tried but I am just guessing.

                          def get_pipeline():
                          pipeline = dai.Pipeline()

                              # # Define a source - color camera
                              cam = pipeline.createColorCamera()
                              cam.setBoardSocket(dai.CameraBoardSocket.RGB)
                              # cam.setInterleaved(False)
                              cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_48_MP)
                              cam.setVideoSize(1920, 1080)
                              cam.initialControl.setSceneMode(dai.CameraControl.SceneMode.FACE_PRIORITY)
                          
                              # Create MobileNet detection network
                              mobilenet = pipeline.create(dai.node.MobileNetDetectionNetwork)
                              mobilenet.setBlobPath(
                                  blobconverter.from_zoo(name="face-detection-retail-0004", shaves=3)
                              )
                              mobilenet.setConfidenceThreshold(0.7)
                          
                              #
                          
                              manipRgb = pipeline.createImageManip()
                              rgbRr = dai.RotatedRect()
                              rgbRr.center.x, rgbRr.center.y = cam.getPreviewWidth() // 2, cam.getPreviewHeight() // 2
                              rgbRr.size.width, rgbRr.size.height = cam.getPreviewHeight(), cam.getPreviewWidth()
                              rgbRr.angle = 90
                              manipRgb.initialConfig.setCropRotatedRect(rgbRr, False)
                              cam.preview.link(manipRgb.inputImage)
                          
                          
                              #
                          
                              crop_manip = pipeline.create(dai.node.ImageManip)
                              crop_manip.initialConfig.setResize(300, 300)
                              crop_manip.initialConfig.setFrameType(dai.ImgFrame.Type.BGR888p)
                              manipRgb.out.link(crop_manip.inputImage) #added
                              cam.isp.link(crop_manip.inputImage)
                              crop_manip.out.link(mobilenet.input)
                          • erik replied to this.

                            We're those guidelines for posting to the forum or submitting for review?
                            We are using a UVC and I was trying to flip the image before output but I think it needs to be 1920,1080 so it is faulting.. Is it possible to rotate the image from a script?

                            • erik replied to this.

                              Some general feedback here would be great. I do not know enough to ask the right questions yet. We have a camera using UVC and face detection but it was longer than it was tall (1920, 1080) so we wanted to rotate the and camera and stream (1080,1920). When we rotate the camera, the face detection is not looking for the sideways faces so I need to flip the stream before it goes in to that I believe but not before the UVC input? :
                              What is the max camRgb video size? We are using the OAK SOM.

                              import os
                              import sys
                              import time
                              
                              import blobconverter
                              import click
                              import depthai as dai
                              
                              if sys.version_info[0] < 3:
                                  raise Exception["Doesn't work with Py2"]
                              
                              MJPEG = False
                              
                              os.environ["DEPTHAI_LEVEL"] = "debug"
                              
                              progressCalled = False
                              # TODO move this under flash(), will need to handle `progressCalled` differently
                              def progress(p):
                                  global progressCalled
                                  progressCalled = True
                                  print(f"Flashing progress: {p*100:.1f}%")
                              
                              
                              # Will flash the bootloader if no pipeline is provided as argument
                              def flash(pipeline=None):
                                  (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice()
                                  bootloader = dai.DeviceBootloader(bl, True)
                              
                                  startTime = time.monotonic()
                                  if pipeline is None:
                                      print("Flashing bootloader...")
                                      bootloader.flashBootloader(progress)
                                  else:
                                      print("Flashing application pipeline...")
                                      bootloader.flash(progress, pipeline)
                              
                                  if not progressCalled:
                                      raise RuntimeError("Flashing failed, please try again")
                                  elapsedTime = round(time.monotonic() - startTime, 2)
                                  print("Done in", elapsedTime, "seconds")
                              
                              
                              @click.command()
                              @click.option(
                                  "-fb",
                                  "--flash-bootloader",
                                  is_flag=True,
                                  help="Updates device bootloader prior to running",
                              )
                              @click.option(
                                  "-fp",
                                  "--flash-pipeline",
                                  is_flag=True,
                                  help="Flashes pipeline. If bootloader flash is also requested, this will be flashed after",
                              )
                              @click.option(
                                  "-gbs",
                                  "--get-boot-state",
                                  is_flag=True,
                                  help="Prints out the boot state of the connected MX"
                              )
                              def main(flash_bootloader, flash_pipeline, get_boot_state):
                                  
                                  def get_pipeline():
                                      pipeline = dai.Pipeline()
                              
                                      # # Define a source - color camera
                                      cam = pipeline.createColorCamera()
                                      cam.setBoardSocket(dai.CameraBoardSocket.RGB)
                                      cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_48_MP)
                                      cam.setVideoSize(1920, 1080)
                                      cam.initialControl.setSceneMode(dai.CameraControl.SceneMode.FACE_PRIORITY)
                              
                                      # Create MobileNet detection network
                                      mobilenet = pipeline.create(dai.node.MobileNetDetectionNetwork)
                                      mobilenet.setBlobPath(
                                          blobconverter.from_zoo(name="face-detection-retail-0004", shaves=3)
                                      )
                                      mobilenet.setConfidenceThreshold(0.7)
                              
                                      crop_manip = pipeline.create(dai.node.ImageManip)
                                      crop_manip.initialConfig.setResize(300, 300)
                                      crop_manip.initialConfig.setFrameType(dai.ImgFrame.Type.BGR888p)
                                      cam.isp.link(crop_manip.inputImage)
                                      crop_manip.out.link(mobilenet.input)
                              
                                      # Create an UVC (USB Video Class) output node. It needs 1920x1080, NV12 input
                                      uvc = pipeline.createUVC()
                                      cam.video.link(uvc.input)
                              
                                      # Script node
                                      script = pipeline.create(dai.node.Script)
                                      mobilenet.out.link(script.inputs["dets"])
                                      script.outputs["cam_cfg"].link(cam.inputConfig)
                                      script.outputs["cam_ctrl"].link(cam.inputControl)
                                      script.setScript(
                                      """
                                      ORIGINAL_SIZE = (5312, 6000) # 48MP with size constraints described on IMX582 luxonis page
                                      SCENE_SIZE = (1920, 1080) # 1080P
                                      x_arr = []
                                      y_arr = []
                                      AVG_MAX_NUM=7
                                      limits = [0, 0] # xmin and ymin limits
                                      limits.append((ORIGINAL_SIZE[0] - SCENE_SIZE[0]) / ORIGINAL_SIZE[0]) # xmax limit
                                      limits.append((ORIGINAL_SIZE[1] - SCENE_SIZE[1]) / ORIGINAL_SIZE[1]) # ymax limit
                                      cfg = ImageManipConfig()
                                      ctrl = CameraControl()
                                      def average_filter(x, y):
                                          x_arr.append(x)
                                          y_arr.append(y)
                                          if AVG_MAX_NUM < len(x_arr): x_arr.pop(0)
                                          if AVG_MAX_NUM < len(y_arr): y_arr.pop(0)
                                          x_avg = 0
                                          y_avg = 0
                                          for i in range(len(x_arr)):
                                              x_avg += x_arr[i]
                                              y_avg += y_arr[i]
                                          x_avg = x_avg / len(x_arr)
                                          y_avg = y_avg / len(y_arr)
                                          if x_avg < limits[0]: x_avg = limits[0]
                                          if y_avg < limits[1]: y_avg = limits[1]
                                          if limits[2] < x_avg: x_avg = limits[2]
                                          if limits[3] < y_avg: y_avg = limits[3]
                                          return x_avg, y_avg
                                      while True:
                                          dets = node.io['dets'].get().detections
                                          if len(dets) == 0: continue
                                           coords = dets[0] # take first
                                          # Get detection center
                                          x = (coords.xmin + coords.xmax) / 2
                                          y = (coords.ymin + coords.ymax) / 2
                                          x -= SCENE_SIZE[0] / ORIGINAL_SIZE[0] / 2
                                          y -= SCENE_SIZE[1] / ORIGINAL_SIZE[1] / 2
                                          # node.warn(f"{x=} {y=}")
                                          x_avg, y_avg = average_filter(x,y)
                                          
                                          # node.warn(f"{x_avg=} {y_avg=}")
                                          cfg.setCropRect(x_avg, y_avg, 0, 0)
                                          node.io['cam_cfg'].send(cfg)
                                          node.io['cam_ctrl'].send(ctrl)
                                      """
                                      )
                                      return pipeline
                              
                                  if flash_bootloader or flash_pipeline:
                                      if flash_bootloader: flash()
                                      if flash_pipeline: flash(get_pipeline())
                                      print("Flashing successful. Please power-cycle the device")
                                      quit()
                              
                                  if get_boot_state:
                                      (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice()
                                      print(f"Device state: {bl.state.name}")
                              
                              
                                  # with dai.Device(get_pipeline(), usb2Mode=True) as dev:
                                  with dai.Device(get_pipeline()) as dev:
                                      print(f"Connection speed: {dev.getUsbSpeed()}")
                              
                                      # Doing nothing here, just keeping the host feeding the watchdog
                                      while True:
                                          try:
                                              time.sleep(0.1)
                                          except KeyboardInterrupt:
                                              break
                              
                              
                              if __name__ == "__main__":
                                  try:
                                      main()
                                  except KeyboardInterrupt:
                                      sys.exit(0)

                              Hi chandrian ,
                              For UVC, I believe the current limitation is that frames need to be 720P and in NV12 format, so you would likely need to rotate the image after retrieving it on the host, or use some other option (eg streaming via dephtai library, then creating virtual camera on the host). Would that work for your application?
                              THanks, Erik