title: How to combine two yolov3 models for object detection?
body: <p>We have two yolov3-tiny models for license plate detection.The first yolov3-tiny model detecting licence plate on cars and cropping it for the second yolov3-tiny model, then should send these output cropped images to the second yolov3-tiny model as input images. The second yolov3-tiny model should have receive these cropped images as input for detecting country region.
  We have a problem with combining two models. Any advice and help is appreciated.
  The code below:</p>
  
  <pre><code># This code is written at BigVision LLC. It is based on the OpenCV project. It is subject to the license terms in the LICENSE file found in this distribution and at http://opencv.org/license.html
  
  # Usage example:  python3 object_detection_yolo.py --video=run.mp4
  #                 python3 object_detection_yolo.py --image=bird.jpg
  
  import cv2 as cv
  import argparse
  import sys
  import numpy as np
  import os.path
  
  # Initialize the parameters
  confThreshold = 0.5  #Confidence threshold
  nmsThreshold = 0.4   #Non-maximum suppression threshold
  inpWidth = 608       #Width of network's input image
  inpHeight = 608      #Height of network's input image
  
  parser = argparse.ArgumentParser(description='Object Detection using YOLO in OPENCV')
  parser.add_argument('--image', help='Path to image file.')
  parser.add_argument('--video', help='Path to video file.')
  args = parser.parse_args()
  
  # Load names of classes
  classesFile = "obj.names"
  classes = None
  with open(classesFile, 'rt') as f:
      classes = f.read().rstrip('\n').split('\n')
  
  # Load names of classes
  classesFile1 = "obj1.names"
  classes1 = None
  with open(classesFile1, 'rt') as f:
      classes1 = f.read().rstrip('\n').split('\n')
  
  # Give the configuration and weight files for the model and load the network using them.
  modelConfiguration = "yolov3-tiny_obj.cfg"
  modelWeights = "yolov3-tiny_obj_final.weights"
  
  # Give the configuration and weight files for the model and load the network using them.
  modelConfiguration1 = "yolov3-tiny_obj1.cfg"
  modelWeights1 = "yolov3-tiny_obj_final1.weights"
  
  net = cv.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
  net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
  net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
  
  net1 = cv.dnn.readNetFromDarknet(modelConfiguration1, modelWeights1)
  net1.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
  net1.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
  
  # Get the names of the output layers
  def getOutputsNames(net):
      # Get the names of all the layers in the network
      layersNames = net.getLayerNames()
      # Get the names of the output layers, i.e. the layers with unconnected outputs
      return [layersNames[i[0] - 1] for i in net.getUnconnectedOutLayers()]
  #====================================================================================
  # Get the names of the output layers
  def getOutputsNames1(net1):
      # Get the names of all the layers in the network
      layersNames = net1.getLayerNames()
      # Get the names of the output layers, i.e. the layers with unconnected outputs
      return [layersNames[i[0] - 1] for i in net1.getUnconnectedOutLayers()]
  #====================================================================================
  # Draw the predicted bounding box
  def drawPred(classId, conf, left, top, right, bottom):
      # Draw a bounding box.
      cv.rectangle(frame, (left, top), (right, bottom), (255, 178, 50), 3)
  
      label = '%.2f' % conf
  
      # Get the label for the class name and its confidence
      if classes:
          assert(classId &lt; len(classes))
          label = '%s:%s' % (classes[classId], label)
  
      #Display the label at the top of the bounding box
      labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
      top = max(top, labelSize[1])
      cv.rectangle(frame, (left, top - round(1.5*labelSize[1])), (left + round(1.5*labelSize[0]), top + baseLine), (255, 255, 255), cv.FILLED)
  
      cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0,0,0), 1)
  #=====================================================================================================================================
  def drawPred1(classId, conf, left, top, right, bottom):
      # Draw a bounding box.
      cv.rectangle(crop, (left, top), (right, bottom), (255, 178, 50), 3)
  
      label = '%.2f' % conf
  
      # Get the label for the class name and its confidence
      if classes1:
          assert(classId &lt; len(classes1))
          label = '%s:%s' % (classes1[classId], label)
  
      #Display the label at the top of the bounding box
      labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
      top = max(top, labelSize[1])
      cv.rectangle(crop, (left, top - round(1.5*labelSize[1])), (left + round(1.5*labelSize[0]), top + baseLine), (255, 255, 255), cv.FILLED)
  
      cv.putText(crop, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0,0,0), 1)
  
  # Remove the bounding boxes with low confidence using non-maxima suppression
  crop = ''
  def postprocess(frame, outs):
      frameHeight = frame.shape[0]
      frameWidth = frame.shape[1]
      # Scan through all the bounding boxes output from the network and keep only the
      # ones with high confidence scores. Assign the box's class label as the class with the highest score.
      classIds = []
      confidences = []
      boxes = []
      global crop
  
      for out in outs:
          for detection in out:
              scores = detection[5:]
              classId = np.argmax(scores)
              confidence = scores[classId]
              if confidence &gt; confThreshold:
                  center_x = int(detection[0] * frameWidth)
                  center_y = int(detection[1] * frameHeight)
                  width = int(detection[2] * frameWidth)
                  height = int(detection[3] * frameHeight)
                  left = int(center_x - width / 2)
                  top = int(center_y - height / 2)
                  classIds.append(classId)
                  confidences.append(float(confidence))
                  boxes.append([left, top, width, height])
      print('this is: ', classIds, confidence, boxes)
      # Perform non maximum suppression to eliminate redundant overlapping boxes with
      # lower confidences.
      indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)
      for i in indices:
          i = i[0]
          box = boxes[i]
          left = box[0]
          top = box[1]
          width = box[2]
          height = box[3]
          drawPred(classIds[i], confidences[i], left, top, left + width, top + height)
          # print(left,top,width,height)
          #координаты y1=top, y2=top+height, x1=left, x2=left+width
          #срез frame по указанным координатам и копирование в папку
          crop = frame[top:top + height+1, left:left + width+1].copy()
          # print("//////////////////////", type(crop))
          cv.imwrite("/DISK/KrisServis/CNN/dark/darknet/detect_yolov3_spp/1.jpg", crop)
  
      #=======================================================================================================================================================
  def post(crop, outs1):
      cropHeight = crop.shape[0]
      cropWidth = crop.shape[1]
      # Scan through all the bounding boxes output from the network and keep only the
      # ones with high confidence scores. Assign the box's class label as the class with the highest score.
      classIds_for_crop = []
      confidences_crop = []
      boxes_crop = []
      for out in outs1:
          # print('this is out: ', out)
          for detection in out:
              scores = detection[5:]
              classId = np.argmax(scores)
              print('scores', classId)
              confidence_crop = scores[classId]
              if confidence_crop &gt; confThreshold:
                  center_x = int(detection[0] * cropWidth)
                  center_y = int(detection[1] * cropHeight)
                  width = int(detection[2] * cropWidth)
                  height = int(detection[3] * cropHeight)
                  left = int(center_x - width / 2)
                  top = int(center_y - height / 2)
                  classIds_for_crop.append(classId)
                  confidences_crop.append(float(confidence_crop))
                  boxes_crop.append([left, top, width, height])
      # Perform non maximum suppression to eliminate redundant overlapping boxes with
      # lower confidences.
      print('all ', confidence_crop, boxes_crop, classIds_for_crop)
      indices = cv.dnn.NMSBoxes(boxes_crop, confidences_crop, confThreshold, nmsThreshold)
      for i in indices:
          i = i[0]
          box = boxes_crop[i]
          left = box[0]
          top = box[1]
          width = box[2]
          height = box[3]
          drawPred1(classIds_for_crop[i], confidences_crop[i], left, top, left + width, top + height)
          # print('this is: l t w h', left,top,width,height)
  # Process inputs
  winName = 'Deep learning object detection in OpenCV'
  cv.namedWindow(winName, cv.WINDOW_NORMAL)
  
  outputFile = "yolo_out_py.avi"
  if (args.image):
      # Open the image file
      if not os.path.isfile(args.image):
          print("Input image file ", args.image, " doesn't exist")
          sys.exit(1)
  # =========================================================================================================
      # Подгрузка видео
      cap = cv.VideoCapture(args.image)
      outputFile = args.image[:-4]+'_yolo_out_py.jpg'
  elif (args.video):
      # Open the video file
      if not os.path.isfile(args.video):
          print("Input video file ", args.video, " doesn't exist")
          sys.exit(1)
      cap = cv.VideoCapture(args.video)
      outputFile = args.video[:-4]+'_yolo_out_py.avi'
  else:
      # Webcam input
      cap = cv.VideoCapture(0)
  
  # Get the video writer initialized to save the output video
  if (not args.image):
      vid_writer = cv.VideoWriter(outputFile, cv.VideoWriter_fourcc('M','J','P','G'), 30, (round(cap.get(cv.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv.CAP_PROP_FRAME_HEIGHT))))
  
  while cv.waitKey(1) &lt; 0:
  
      # get frame from the video
      hasFrame, frame = cap.read()
  
      # Stop the program if reached end of video
      if not hasFrame:
          print("Done processing !!!")
          print("Output file is stored as ", outputFile)
          cv.waitKey(3000)
          # Release device
          cap.release()
          break
  
      # Create a 4D blob from a frame.
      blob = cv.dnn.blobFromImage(frame, 1/255, (inpWidth, inpHeight), [0,0,0], 1, crop=False)
      # blob1 = cv.dnn.blobFromImage(, 1/255, (inpWidth, inpHeight), [0,0,0], 1, crop=False)
  
  
      # Sets the input to the network
      net.setInput(blob)
      # net1.setInput(blob1)
  
      # Runs the forward pass to get output of the output layers
      outs = net.forward(getOutputsNames(net))
      # outs1 = net1.forward(getOutputsNames1(net1))
      # Remove the bounding boxes with low confidence
  
      postprocess(frame, outs)
  
      blob1 = cv.dnn.blobFromImage(crop, 1/255, (inpWidth, inpHeight), [0,0,0], 1, crop=False)
      # print('this is blob1',blob1)
      net1.setInput(blob1)
      outs1 = net1.forward(getOutputsNames1(net1))
      # print('this is outs1',outs1)
      post(crop, outs1)
      # Put efficiency information. The function getPerfProfile returns the overall time for inference(t) and the timings for each of the layers(in layersTimes)
      t, _ = net.getPerfProfile()
      # t1, _1 = net1.getPerfProfile()
  
      # label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency())
      # cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))
  
      # Write the frame with the detection boxes
      if (args.image):
          cv.imwrite(outputFile, crop.astype(np.uint8))
      else:
          vid_writer.write(frame.astype(np.uint8))
  
      cv.imshow(winName, frame)
      # cv.imshow(winName, crop)
      cv.waitKey()
  </code></pre>