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:
- Am I following the right methodology to getting the gi and gstreamer modules to work?
- 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?