0

I was having issues getting started with some computer vision related tasks. Right off the bat let me provide a link to the GitHub repo I went to in order to clone my project from: Link to GitHub Repo for Cloning. I was following their README in order to get started. Once done cloning, I followed the first example code by changing directory into my folder with the cloned code and entered this snippet into bash terminal:

sh install_requirements.sh

That seemed to have worked although it gave me a sudo: command not found but it wasn't detrimental to the installation so I continued. The problem then came when I did the next step from the GitHub repo. I entered the following snippet next:

python bodypix.py

For reference I am on Windows 11 so I didn't write python3 so that it'd work. It began the process of beginning to run the python file but I quickly ran into this issue:

 $ python bodypix.py
Traceback (most recent call last):
  File "C:\Users\zalta\Desktop\project-bodypix\bodypix.py", line 28, in <module>
    import gstreamer
  File "C:\Users\zalta\Desktop\project-bodypix\gstreamer.py", line 20, in <module>
    import gi
ModuleNotFoundError: No module named 'gi'

Just for reference, here is the bodypix.py file (although if you clone the repo with the link above you should be able to view it):

# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import time
import svgwrite
import re
import PIL
import argparse
from functools import partial
from collections import deque

import numpy as np
import scipy.ndimage
import scipy.misc
from PIL import Image

import gstreamer
from pose_engine import PoseEngine, EDGES, BODYPIX_PARTS

# Color mapping for bodyparts
RED_BODYPARTS = [k for k,v in BODYPIX_PARTS.items() if "right" in v]
GREEN_BODYPARTS = [k for k,v in BODYPIX_PARTS.items() if "hand" in v or "torso" in v]
BLUE_BODYPARTS = [k for k,v in BODYPIX_PARTS.items() if "leg" in v or "arm" in v or "face" in v or "hand" in v]

def shadow_text(dwg, x, y, text, font_size=16):
    dwg.add(dwg.text(text, insert=(x + 1, y + 1), fill='black',
                     font_size=font_size, style='font-family:sans-serif'))
    dwg.add(dwg.text(text, insert=(x, y), fill='white',
                     font_size=font_size, style='font-family:sans-serif'))

def draw_pose(dwg, pose, color='blue', threshold=0.2):
    xys = {}
    for label, keypoint in pose.keypoints.items():
        if keypoint.score < threshold: continue
        xys[label] = (int(keypoint.yx[1]), int(keypoint.yx[0]))
        dwg.add(dwg.circle(center=(int(keypoint.yx[1]), int(keypoint.yx[0])), r=5,
                           fill='cyan', stroke=color))
    for a, b in EDGES:
        if a not in xys or b not in xys: continue
        ax, ay = xys[a]
        bx, by = xys[b]
        dwg.add(dwg.line(start=(ax, ay), end=(bx, by), stroke=color, stroke_width=2))

class Callback:
  def __init__(self, engine, anonymize=True, bodyparts=True):
    self.engine = engine
    self.anonymize = anonymize
    self.bodyparts = bodyparts
    self.background_image = None
    self.last_time = time.monotonic()
    self.frames = 0
    self.sum_fps = 0
    self.sum_process_time = 0
    self.sum_inference_time = 0

  def __call__(self, image, svg_canvas):
    start_time = time.monotonic()
    inference_time, poses, heatmap, bodyparts = self.engine.DetectPosesInImage(image)

    def clip_heatmap(heatmap, v0, v1):
      a = v0 / (v0 - v1);
      b = 1.0 / (v1 - v0);
      return np.clip(a + b * heatmap, 0.0, 1.0);

    # clip heatmap to create a mask
    heatmap = clip_heatmap(heatmap,  -1.0,  1.0)

    if self.bodyparts:
      rgb_heatmap = np.dstack([
            heatmap*(np.sum(bodyparts[:,:,RED_BODYPARTS], axis=2)-0.5)*100,
            heatmap*(np.sum(bodyparts[:,:,GREEN_BODYPARTS], axis=2)-0.5)*100,
            heatmap*(np.sum(bodyparts[:,:,BLUE_BODYPARTS], axis=2)-0.5)*100,
          ])
    else:
      rgb_heatmap = np.dstack([heatmap[:,:]*100]*3)
      rgb_heatmap[:,:,1:] = 0 # make it red

    rgb_heatmap= 155*np.clip(rgb_heatmap, 0, 1)
    rescale_factor = [
      image.shape[0]/heatmap.shape[0],
      image.shape[1]/heatmap.shape[1],
      1]

    rgb_heatmap = scipy.ndimage.zoom(rgb_heatmap, rescale_factor, order=0)

    if self.anonymize:
      if self.background_image is None:
        self.background_image = np.float32(np.zeros_like(image))
      # Estimate instantaneous background
      mask = np.clip(np.sum(rgb_heatmap, axis=2), 0, 1)[:,:,np.newaxis]
      background_estimate = (self.background_image*mask+ image*(1.0-mask))

      # Mix into continuous estimate with decay
      ratio = 1/max(1,self.frames/2.0)
      self.background_image = self.background_image*(1.0-ratio) + ratio*background_estimate
    else:
      self.background_image = image

    output_image = self.background_image + rgb_heatmap
    int_img = np.uint8(np.clip(output_image,0,255))

    end_time = time.monotonic()

    self.frames += 1
    self.sum_fps += 1.0 / (end_time - self.last_time)
    self.sum_process_time += 1000 * (end_time - start_time) - inference_time
    self.sum_inference_time += inference_time
    self.last_time = end_time
    text_line = 'PoseNet: %.1fms Frame IO: %.2fms TrueFPS: %.2f Nposes %d' % (
        self.sum_inference_time / self.frames,
        self.sum_process_time / self.frames,
        self.sum_fps / self.frames,
        len(poses)
    )

    shadow_text(svg_canvas, 10, 20, text_line)
    for pose in poses:
        draw_pose(svg_canvas, pose)
    print(text_line)
    return int_img

def main():
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--mirror', help='flip video horizontally', action='store_true')
    parser.add_argument('--model', help='.tflite model path.', required=False)
    parser.add_argument('--width', help='Source width', default='640')
    parser.add_argument('--height', help='Source height', default='480')
    parser.add_argument('--videosrc', help='Which video source to use', default='/dev/video0')

    parser.add_argument('--anonymize', dest='anonymize', action='store_true', help='Use anonymizer mode [--noanonymize]')
    parser.add_argument('--noanonymize', dest='anonymize', action='store_false', help=argparse.SUPPRESS)
    parser.set_defaults(anonymize=False)

    parser.add_argument('--bodyparts', dest='bodyparts', action='store_true', help='Color by bodyparts [--nobodyparts]')
    parser.add_argument('--nobodyparts', dest='bodyparts', action='store_false', help=argparse.SUPPRESS)
    parser.set_defaults(bodyparts=True)

    parser.add_argument('--h264', help='Use video/x-h264 input', action='store_true')
    parser.add_argument('--jpeg', help='Use video/jpeg input', action='store_true')
    args = parser.parse_args()

    if args.h264 and args.jpeg:
        print('Error: both mutually exclusive options h264 and jpeg set')
        sys.exit(1)

    default_model = 'models/bodypix_mobilenet_v1_075_640_480_16_quant_decoder_edgetpu.tflite'
    model = args.model if args.model else default_model
    print('Model: {}'.format(model))

    engine = PoseEngine(model)
    inference_size = (engine.image_width, engine.image_height)
    print('Inference size: {}'.format(inference_size))

    src_size = (int(args.width), int(args.height))
    if args.videosrc.startswith('/dev/video'):
        print('Source size: {}'.format(src_size))

    gstreamer.run_pipeline(Callback(engine,
                                    anonymize=args.anonymize,
                                    bodyparts=args.bodyparts),
                           src_size, inference_size,
                           mirror=args.mirror,
                           videosrc=args.videosrc,
                           h264=args.h264,
                           jpeg=args.jpeg)


if __name__ == '__main__':
    main()

So I decided to tried scouring Stack Overflow in an attempt to understand what was wrong. I found a link: stack reponse. I tried following the official PyGObject documentation from the answer with the most upvotes and I successfully got the GUI to pop up for me from the instructions that person gave in the other stack post. I thought that'd do the trick to get the "gi" and "gstreamer" modules from PyGObject. But I got the same ModuleNotFound error. I thought it might be because PyGObject wasn't correctly installed. So I tried pip install pygobject to see if that was the reason it wasn't getting the submodules. I then ran into another problem:

$ pip install pygobject
Collecting pygobject
  Using cached PyGObject-3.42.2.tar.gz (719 kB)
  Installing build dependencies: started
  Installing build dependencies: finished with status 'done'
  Getting requirements to build wheel: started
  Getting requirements to build wheel: finished with status 'done'
  Preparing metadata (pyproject.toml): started
  Preparing metadata (pyproject.toml): finished with status 'done'
Requirement already satisfied: pycairo>=1.16.0 in c:\users\zalta\appdata\local\programs\python\python310\lib\site-packages (from pygobject) (1.21.0)
Building wheels for collected packages: pygobject
  Building wheel for pygobject (pyproject.toml): started
  Building wheel for pygobject (pyproject.toml): finished with status 'error'
  error: subprocess-exited-with-error

  Building wheel for pygobject (pyproject.toml) did not run successfully.
  exit code: 1

  [41 lines of output]
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build\lib.win-amd64-cpython-310
  creating build\lib.win-amd64-cpython-310\pygtkcompat
  copying pygtkcompat\generictreemodel.py -> build\lib.win-amd64-cpython-310\pygtkcompat
  copying pygtkcompat\pygtkcompat.py -> build\lib.win-amd64-cpython-310\pygtkcompat
  copying pygtkcompat\__init__.py -> build\lib.win-amd64-cpython-310\pygtkcompat
  creating build\lib.win-amd64-cpython-310\gi
  copying gi\docstring.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\importer.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\module.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\pygtkcompat.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\types.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_constants.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_error.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_gtktemplate.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_option.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_ossighelper.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_propertyhelper.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\_signalhelper.py -> build\lib.win-amd64-cpython-310\gi
  copying gi\__init__.py -> build\lib.win-amd64-cpython-310\gi
  creating build\lib.win-amd64-cpython-310\gi\repository
  copying gi\repository\__init__.py -> build\lib.win-amd64-cpython-310\gi\repository
  creating build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\Gdk.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\GdkPixbuf.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\GIMarshallingTests.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\Gio.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\GLib.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\GObject.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\Gtk.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\keysyms.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\Pango.py -> build\lib.win-amd64-cpython-310\gi\overrides
  copying gi\overrides\__init__.py -> build\lib.win-amd64-cpython-310\gi\overrides
  running build_ext
  pycairo: trying include directory: 'C:\\Users\\zalta\\AppData\\Local\\Temp\\pip-build-env-_o7xhh8o\\overlay\\Lib\\site-packages\\cairo\\include'
  pycairo: found 'C:\\Users\\zalta\\AppData\\Local\\Temp\\pip-build-env-_o7xhh8o\\overlay\\Lib\\site-packages\\cairo\\include\\py3cairo.h'
  building 'gi._gi' extension
  error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
  [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for pygobject
Failed to build pygobject
ERROR: Could not build wheels for pygobject, which is required to install pyproject.toml-based projects

The obvious thing I noticed was the C++ version but I am not sure why it couldn't build the wheels. I've been reading this error message and I'm not sure what exactly is causing it. I don't even know if this is the proper way to being able to access the 'gi' and 'gstreamer' modules to be honest this was just another poke at it from stack overflow. I was wondering:

  1. Am I following the right methodology to getting the gi and gstreamer modules to work?
  2. If it's not how exactly to go about getting the 2 modules to work, could I get help figuring out what it is I need to do to get them working?
torek
  • 448,244
  • 59
  • 642
  • 775

0 Answers0