Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
guillain committed Dec 29, 2019
0 parents commit 28940c2
Show file tree
Hide file tree
Showing 14 changed files with 33,698 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.idea
*.log
*.json
*pyc*
.env
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM jjanzic/docker-python3-opencv:latest
# RPI: FROM sgtwilko/rpi-raspbian-opencv:latest

WORKDIR /src

COPY requirements.txt /src/requirements.txt

RUN pip install --upgrade pip && \
pip install -r requirements.txt

COPY src/ /src

CMD ["/bin/bash"]
13 changes: 13 additions & 0 deletions Dockerfile-rpi
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM sgtwilko/rpi-raspbian-opencv:latest
#FROM mohaseeb/raspberrypi3-python-opencv:latest

WORKDIR /src

COPY requirements.txt /src/requirements.txt

RUN pip install --upgrade pip && \
pip install -r requirements.txt

COPY src/ /src

CMD ["/bin/bash"]
5 changes: 5 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Copyright (c) 2019 Guillain Sanchez <[email protected]>

Private License

Distribution not allowed
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# gPhoto-object-extraction
_How to run easily the object recognition_

For the demo and to make it more funny:
- the source of information (means the photo galery) is *Google Photo*!
- the object recognized are stored on *AWS S3*!
- all run in docker :)
- ... compatible with Raspberry

## Pre-requisite
- Docker host
- Internet access

## Easy Run
After have cloned the repository localy (`git clone https://github.com/guillain/gPhoto-object-extraction`)
and enter in the new directory (`cd gPhoto-object-extraction`) execute the following commands:

1/ create your own confguration file:
- `cp sample.env .env && vi .env` and add your AWS credentials info
- import the files `google-photo.json` and `google-photo-token.json` as GCP credentials info
- if you need to run it on Raspberry, invert the comment on the first two lines in the `Dockerfile`

2/ execute the container with the desired date for your Google Photos: `./run "29/12/2019"`


## Support
- Original post:
- https://www.hackster.io/mjrobot/real-time-face-recognition-an-end-to-end-project-a10826
- https://github.com/Mjrovai/OpenCV-Face-Recognition
- Raspberry: https://www.raspberrypi.org
- Docker: https://www.docker.com
- OpenCV: https://opencv.org
10 changes: 10 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tensorflow
python-forecastio
opencv-python==4.1.0.25
awscli
boto3
numpy
google-api-python-client
httplib2
oauth2client
python-dotenv
32 changes: 32 additions & 0 deletions run
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
. .env

# my_date=${1} if not provided, go in bash

# Name of the container (to build & run)
NAME="gphoto-object-extraction"

# If no date, go in console
if [ "${1}" == "" ]; then
echo -e '\n/!\ No date provided, we jump in the console (exit to go out) /!\ \n'
RUN="/bin/bash"
else
RUN="python app.py"
fi

# Build the image
docker build -t ${NAME} .

# Test the image and the cv2 import
docker run -it --rm ${NAME} python -c "import cv2; print(cv2.__version__)"

# Run the app
docker run -it --rm \
-e my_date=${1} \
--env-file=`pwd`/.env \
-v `pwd`/google-photo.json:/src/google-photo.json \
-v `pwd`/google-photo-token.json:/src/google-photo-token.json \
${NAME} ${RUN}

# Done & Bye
exit 0
7 changes: 7 additions & 0 deletions sample.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
aws_s3_bucket=my_obects
aws_region_name=eu-central-1
aws_key_id=
aws_access_key=

gcp_ident_file=google-photo.json
gcp_token_file=google-photo-token.json
22 changes: 22 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from setuptools import setup, find_packages

NAME="gPhoto-object-extraction"
__version__ = '1.0.0'
AUTHOR="Guillain"
AUTHOR_EMAIL="[email protected]"

with open('requirements.txt') as f:
requirements = f.read().splitlines()

setup(
name=NAME,
version=__version__,
description="Image analysis with IA",
url='https://gitlab.com/bo-art-of-bonsai/' + NAME,
author=AUTHOR,
author_email=AUTHOR_EMAIL,
license='Private',
install_requires=requirements,
packages=find_packages(),
zip_safe=False
)
69 changes: 69 additions & 0 deletions src/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python
# -*- encoding: utf-8
import os
import requests

from lib.aws import AWS
from lib.opencv import OpenCV
from lib.gcp import GCP

from dotenv import load_dotenv
load_dotenv()


def main(my_date):
# my_date = "29/11/2019"

# Instancies
aws = AWS(bucket=os.getenv('aws_s3_bucket'))
gcp = GCP(cred_file=os.getenv('gcp_token_file'))
cv = OpenCV()

# Get list of photos
photos = gcp.listMedia(date_filter=my_date, media_type=["PHOTO"])
if photos is None:
print('error', 'No photos found, exit')
exit(0)
print('{} photos found'.format(len(photos)))

# For each photo: download, extract each face and store individual face in S3
face_catalog = []
for photo in photos:
# Download photo data
photo_data = requests.get(photo['baseUrl']).content
with open(photo['filename'], 'wb') as handler:
handler.write(photo_data)

faces = cv.extract_faces(photo['filename'])
#faces = cv.extract_faces_from_buffer(photo_data)

i_face = 1
for face in faces:
filename = 'extract/{}'.format(face)

aws.s3_upload_file(face, filename)
os.remove(face)
#aws.s3_upload_data(face, filename)

face = dict(photo)
face['face_id'] = i_face
face['face_filename'] = filename
#del face['baseUrl']
face_catalog.append(face)

i_face = i_face + 1

os.remove(photo['filename'])
print('{} face(s) found in the photo {}'.format(i_face - 1, photo['filename']))

if face_catalog:
for face in face_catalog:
print('JSON catalog of faces\n{}'.format(face))
print('{} face(s) found in total'.format(len(face_catalog)))
else:
print('No face found :(')


if __name__ == '__main__':
main(os.getenv('my_date'))

42 changes: 42 additions & 0 deletions src/lib/aws.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import os
import boto3
from io import BytesIO


class AWS(object):
def __init__(self,
type='s3',
region=os.getenv('aws_region_name'),
key_id=os.getenv('aws_key_id'),
access_key=os.getenv('aws_access_key'),
bucket='bo-infra-backup'):
self.region_name = region
self.bucket_name = bucket

self.session = boto3.Session(
aws_access_key_id=key_id,
aws_secret_access_key=access_key)

def init(self, type='s3', obj='resource'):
if obj == 'resource':
return self.session.resource(type, region_name=self.region_name)
elif obj == 'client':
return self.session.client(type, region_name=self.region_name)

def s3_download(self, file, output):
s3 = self.init(type='s3', obj='resource')
file_stream = BytesIO()

s3.Object(self.bucket_name, file).download_file(output)
s3.Object(self.bucket_name, file).download_fileobj(file_stream)

def s3_upload_file(self, file_in, file_out):
s3 = self.init(type='s3', obj='resource')

s3.Bucket(self.bucket_name).upload_file(Filename=file_in, Key=file_out)

def s3_upload_data(self, data, filename):
s3 = self.init(type='s3', obj='resource')

s3.Object(self.bucket_name, filename).put(Body=data)

74 changes: 74 additions & 0 deletions src/lib/gcp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import os
from googleapiclient.discovery import build, MediaFileUpload
from httplib2 import Http
from oauth2client import file, client, tools


class GCP(object):
def __init__(self, cred_file, store_file=os.getenv('gcp_ident_file')):
self.store_file = store_file
# self.photo_scopes = 'https://www.googleapis.com/auth/photoslibrary.readonly'
self.photo_scopes = 'https://www.googleapis.com/auth/photoslibrary.sharing'

store = file.Storage(self.store_file)
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets(cred_file, self.photo_scopes)
creds = tools.run_flow(flow, store)

self.lib = build('photoslibrary', 'v1', http=creds.authorize(Http()))

def format_date(self, my_date):
# my_date = "27/12/2019"

my_date_arr = my_date.split('/')
return [{"day": my_date_arr[0], "month": my_date_arr[1], "year": my_date_arr[2]}]

def listMedia(self, date_filter=None, media_type=["PHOTO", "VIDEO"]):
# date_filter = "27/12/2019" or "0/12/2019" for all days of december

nextpagetoken = 'Dummy'
filters = { "mediaTypeFilter": {"mediaTypes": media_type} }
if date_filter is not None:
filters = {
"dateFilter": {"dates": self.format_date(date_filter)},
"mediaTypeFilter": {"mediaTypes": media_type}
}

res = []
while nextpagetoken != '':
nextpagetoken = '' if nextpagetoken == 'Dummy' else nextpagetoken
results = self.lib.mediaItems().search(
body={
"filters": filters,
"pageSize": 100,
"pageToken": nextpagetoken,
}
).execute()

# The default number of media items to return at a time is 25. The maximum pageSize is 100.
items = results.get('mediaItems', [])
nextpagetoken = results.get('nextPageToken', '')
for item in items:
res.append(item)

return res

def uploadMedia(self, media, name='', mimetype='image/png'):
media = MediaFileUpload(media, mimetype=mimetype, resumable=True)
request = self.lib.create(media_body=media, body={'name': name})
response = None
while response is None:
status, response = request.next_chunk()

return response

def listAlbums(self):
r = self.lib.albums().list(pageSize=10).execute()
items = r.get('albums', [])
return items

def createAlbum(self, title):
r = self.lib.albums().create(body={'album':{'title':title}}).execute()
return r.id

Loading

0 comments on commit 28940c2

Please sign in to comment.