class_docstr: OpenImagesReader supports reading the images directly from the original
  data source which is hosted in Google Cloud Storage.
  
  Before using it you have to request and configure access following the
  instructions here: https://github.com/cvdfoundation/open-images-dataset
docstr: We have a generator/consumer-generator/consumer setup where we have:
  - one thread to read the file without the images
  - multiple threads to download images and complete the records
  - the main thread to yield the completed records
docstr_tok: ["We","have","a","generator\/consumer-generator\/consumer","setup","where","we","have",":","-","one","thread","to","read","the","file","without","the","images","-","multiple","threads","to","download","images","and","complete","the","records","-","the","main","thread","to","yield","the","completed","records"]
code: def iterate(self):
      """
      We have a generator/consumer-generator/consumer setup where we have:
      - one thread to read the file without the images
      - multiple threads to download images and complete the records
      - the main thread to yield the completed records
      """
      signal.signal(signal.SIGINT, self._stop_reading)
  
      # Which records to complete (missing image)
      partial_records_queue = queue.Queue()
  
      # Limit records queue to 250 because we don't want to end up with all
      # the images in memory.
      records_queue = queue.Queue(maxsize=250)
  
      generator = threading.Thread(
          target=self._queue_partial_records,
          args=(partial_records_queue, records_queue),
      )
      generator.start()
  
      for _ in range(self._download_threads):
          t = threading.Thread(
              target=self._complete_records,
              args=(partial_records_queue, records_queue),
          )
          t.daemon = True
          t.start()
  
      while not self._stop_iteration():
          record = records_queue.get()
  
          if record is None:
              break
  
          self.yielded_records += 1
          yield record
  
      # In case we were killed by signal
      self._empty_queue(partial_records_queue)
      self._empty_queue(records_queue)
  
      # Wait for generator to finish peacefuly...
      generator.join()
  
imports: import csv
  import os
  import signal
  import six
  import sys
  import tensorflow
  import threading
  from six.moves import queue
  from PIL import Image
  from luminoth.tools.dataset.readers import InvalidDataDirectory
  from luminoth.tools.dataset.readers.object_detection import ObjectDetectionReader
  from luminoth.utils.dataset import read_image
label_desc: Use image node_id 12 for calling the OpenImagesReader obj's underlying member method code with example usage: obj.iterate() without return types