This tutorial demonstrates using Knative serving, Cloud Vision API, and ImageMagick to detect and blur offensive images uploaded to a Cloud Storage bucket. This tutorial builds on the tutorial Using Pub/Sub with Knative serving.
This tutorial walks through modifying an existing sample app. You can also download the completed sample if you want.
Setting up gcloud defaults
To configure gcloud with defaults for your Knative serving service:
Set your default project:
gcloud config set project PROJECT_ID
Replace PROJECT_ID with the name of the project you use for this tutorial.
Configure gcloud for your cluster:
gcloud config set run/platform gke gcloud config set run/cluster CLUSTER-NAME gcloud config set run/cluster_location REGION
Replace:
- CLUSTER-NAME with the name you used for your cluster,
- REGION with the supported cluster location of your choice.
Understanding the sequence of operations
The flow of data in this tutorial follows these steps:
- A user uploads an image to a Cloud Storage bucket.
- Cloud Storage publishes a message about the new file to Pub/Sub.
- Pub/Sub pushes the message to the Knative serving service.
- The Knative serving service retrieves the image file referenced in the Pub/Sub message.
- The Knative serving service uses the Cloud Vision API to analyze the image.
- If violent or adult content is detected, the Knative serving service uses ImageMagick to blur the image.
- The Knative serving service uploads the blurred image to another Cloud Storage bucket for use.
Subsequent use of the blurred image is left as an exercise for the reader.
Setting up Cloud Storage buckets
Create a Cloud Storage bucket for uploading images, where INPUT_BUCKET_NAME is a globally unique bucket name:
gcloud storage buckets create gs://INPUT_BUCKET_NAME
The Knative serving service only reads from this bucket.
Create a second Cloud Storage bucket to receive blurred images, where BLURRED_BUCKET_NAME is a globally unique bucket name:
gcloud storage buckets create gs://BLURRED_BUCKET_NAME
The Knative serving service uploads blurred images to this bucket. Using a separate bucket prevents processed images from re-triggering the service.
In the following steps, you create and deploy a service that processes notification of file uploads to the INPUT_BUCKET_NAME. You turn on notification delivery after you deploy and test the service, to avoid premature invocation of the new service.
Modifying the Pub/Sub tutorial sample code
This tutorial builds on the code assembled in the Using Pub/Sub tutorial. If you have not yet completed that tutorial, do so now, skipping the cleanup steps, then return here to add image processing behavior.
Adding image processing code
The image processing code is separated from request handling for readability and ease of testing. To add image processing code:
Change to the directory of the Pub/Sub tutorial sample code.
Add code to import the image processing dependencies, including libraries to integrate with Google Cloud services, ImageMagick, and the file system.
Node.js
Open a newimage.js
file in your editor, and copy in the following:Python
Open a newimage.py
file in your editor, and copy in the following:Go
Open a newimagemagick/imagemagick.go
file in your editor, and copy in the following:Java
Open a newsrc/main/java/com/example/cloudrun/ImageMagick.java
file in your editor, and copy in the following:Add code to receive a Pub/Sub message as an event object and control the image processing.
The event contains data about the originally uploaded image. This code determines if the image needs to be blurred by checking the results of a Cloud Vision analysis for violent or adult content.
Node.js
Python
Go
Java
Retrieve the referenced image from the Cloud Storage input bucket created above, use ImageMagick to transform the image with a blur effect, and upload the result to the output bucket.
Node.js
Python
Go
Java
Integrating image processing into the Pub/Sub sample code
To modify the existing service to incorporate the image processing code:
Add new dependencies for your service, including the Cloud Vision and Cloud Storage client libraries:
Node.js
npm install gm @google-cloud/storage @google-cloud/vision
Python
Add the necessary client libraries so that yourrequirements.txt
will look something like this:Go
The go sample application uses go modules, the new dependencies added above in theimagemagick/imagemagick.go
import statement will automatically download by the next command that needs them.Java
Add the following dependency under<dependencyManagement>
in thepom.xml
: Add the following dependencies under<dependencies>
in thepom.xml
:Add the ImageMagick system package to your container by modifying the
Dockerfile
below theFROM
statement. If using a "multi-stage" Dockerfile, place this in the final stage.Debian/Ubuntu Alpine Read more about working with system packages in your Knative serving service in the Using system packages tutorial.
Replace the existing Pub/Sub message handling code with a function call to our new blurring logic.
Node.js
Theapp.js
file defines the Express.js app and prepares received Pub/Sub messages for use. Make the following changes:- Add code to import the new
image.js
file - Remove the existing "Hello World" code from the route
- Add code to further validate the Pub/Sub message
Add code to call the new image processing function
When you are finished, the code will look like this:
Python
Themain.py
file defines the Flask app and prepares received Pub/Sub messages for use. Make the following changes:- Add code to import the new
image.py
file - Remove the existing "Hello World" code from the route
- Add code to further validate the Pub/Sub message
Add code to call the new image processing function
When you are finished, the code will look like this:
Go
Themain.go
file defines the HTTP service and prepares received Pub/Sub messages for use. Make the following changes:- Add code to import the new
imagemagick.go
file - Remove the existing "Hello World" code from the handler
- Add code to further validate the Pub/Sub message
- Add code to call the new image processing function
Java
ThePubSubController.java
file defines the controller that handles HTTP requests and prepares received Pub/Sub messages for use. Make the following changes:- Add the new imports
- Remove the existing "Hello World" code from the controller
- Add code to further validate the Pub/Sub message
- Add code to call the new image processing function
- Add code to import the new
Downloading the complete sample
To retrieve the complete Image Processing code sample for use:
Clone the sample app repository to your local machine:
Node.js
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Python
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Go
git clone https://github.com/GoogleCloudPlatform/golang-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Java
git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git
Alternatively, you can download the sample as a zip file and extract it.
Change to the directory that contains the Knative serving sample code:
Node.js
cd nodejs-docs-samples/run/image-processing/
Python
cd python-docs-samples/run/image-processing/
Go
cd golang-samples/run/image-processing/
Java
cd java-docs-samples/run/image-processing/
Shipping the code
Shipping code consists of three steps: building a container image with Cloud Build, uploading the container image to Container Registry, and deploying the container image to Knative serving.
To ship your code:
Build your container and publish on Container Registry:
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub
Where PROJECT_ID is your Google Cloud project ID, and
pubsub
is the name you want to give your service.Upon success, you will see a SUCCESS message containing the ID, creation time, and image name. The image is stored in Container Registry and can be re-used if desired.
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub
Where PROJECT_ID is your Google Cloud project ID, and
pubsub
is the name you want to give your service.Upon success, you will see a SUCCESS message containing the ID, creation time, and image name. The image is stored in Container Registry and can be re-used if desired.
Go
gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub
Where PROJECT_ID is your Google Cloud project ID, and
pubsub
is the name you want to give your service.Upon success, you will see a SUCCESS message containing the ID, creation time, and image name. The image is stored in Container Registry and can be re-used if desired.
Java
This sample uses Jib to build Docker images using common Java tools. Jib optimizes container builds without the need for a Dockerfile or having Docker installed. Learn more about building Java containers with Jib.Using the Dockerfile, configure and build a base image with the system packages installed to override Jib's default base image:
gcloud builds submit --tag gcr.io/PROJECT_ID/imagemagick
Where PROJECT_ID is your Google Cloud project ID.
Build your final container with Jib and publish on Container Registry:
mvn compile jib:build \ -Dimage=gcr.io/PROJECT_ID/pubsub \ -Djib.from.image=gcr.io/PROJECT_ID/imagemagick
Where PROJECT_ID is your Google Cloud project ID.
Run the following command to deploy your service, using the same service name you used in the Pub/Sub tutorial:
Node.js
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME
Python
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME
Go
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME
Java
gcloud run deploy pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub --set-env-vars=BLURRED_BUCKET_NAME=BLURRED_BUCKET_NAME --memory 512M
Replace PROJECT_ID with your Google Cloud project ID.
pubsub
is the container name andpubsub-tutorial
is the name of the service. Notice that the container image is deployed to the service and cluster that you configured previously under Setting up gcloud defaults.Replace BLURRED_BUCKET_NAME with your Cloud Storage bucket you created earlier to receive blurred images to set the environment variable.
Wait until the deployment is complete: this can take about half a minute. On success, the command line displays the service URL.
Turning on notifications from Cloud Storage
Configure Cloud Storage to publish a message to a Pub/Sub topic whenever a file (known as an object), is uploaded or changed. Send the notification to the previously created topic so any new file upload will invoke the service.
gcloud storage buckets notifications create gs://INPUT_BUCKET_NAME --topic=myRunTopic --payload-format=json
This command is installed as part of the Google Cloud CLI. myRunTopic
is the
topic you created in the previous tutorial.
Replace INPUT_BUCKET_NAME with the name you used when you created the buckets.
For more details about storage bucket notifications, read object change notifications.
Trying it out
Upload an offensive image, such as this image of a flesh-eating zombie:
gcloud storage cp zombie.jpg gs://INPUT_BUCKET_NAME
where INPUT_BUCKET_NAME is the Cloud Storage bucket you created earlier for uploading images.
Navigate to the service logs:
Navigate to the Knative serving page in the Google Cloud console:
Click the
pubsub-tutorial
service.Select the Logs tab. Logs might take a few moments to appear. If you don't see them immediately, check again after a few moments.
Look for the
Blurred image: zombie.png
message.You can view the blurred images in the BLURRED_BUCKET_NAME Cloud Storage bucket you created earlier: locate the bucket in the Cloud Storage page in the Google Cloud console