ImageMagick-Anleitung


In dieser Anleitung wird gezeigt, wie Sie Cloud Run-Funktionen, die Vision API und ImageMagick verwenden können, um anstößige Bilder, die in einen Cloud Storage-Bucket hochgeladen werden, zu erkennen und unkenntlich zu machen.

Ziele

  • Eine durch Cloud Storage ausgelöste CloudEvent-Funktion bereitstellen
  • Gewaltverherrlichende oder nicht jugendfreie Inhalte mit der Vision API erkennen
  • Anstößige Bilder mit ImageMagick unkenntlich machen
  • Beispielbild hochladen, um die Funktion zu testen

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

  • Cloud Run functions
  • Cloud Storage
  • Cloud Vision
  • Cloud Build
  • Pub/Sub
  • Artifact Registry
  • Eventarc
  • Cloud Logging

For details, see Cloud Run functions pricing.

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen. Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Vorbereitung

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Functions, Cloud Build, Artifact Registry, Eventarc, Cloud Storage, Cloud Vision, Logging, and Pub/Sub APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Cloud Functions, Cloud Build, Artifact Registry, Eventarc, Cloud Storage, Cloud Vision, Logging, and Pub/Sub APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. Wenn Sie die gcloud CLI bereits installiert haben, aktualisieren Sie sie mit dem folgenden Befehl:

    gcloud components update
  13. Bereiten Sie die Entwicklungsumgebung vor.

Datenfluss visualisieren

Der Datenfluss in der Anwendung der ImageMagick-Anleitung umfasst mehrere Schritte:

  1. Ein Bild wird in einen Cloud Storage-Bucket hochgeladen.
  2. Die Cloud Run-Funktion analysiert das Bild mithilfe der Cloud Vision API.
  3. Wenn Inhalte mit Darstellungen von Gewalt oder Inhalte nur für Erwachsene erkannt werden, nutzt die Cloud Run-Funktion ImageMagick, um das Bild unkenntlich zu machen.
  4. Das unkenntlich gemachte Bild wird zur Verwendung in einen anderen Cloud Storage-Bucket hochgeladen.

Anwendung vorbereiten

  1. Erstellen Sie einen regionalen Cloud Storage-Bucket zum Hochladen von Bildern. Dabei ist YOUR_INPUT_BUCKET_NAME ein global eindeutiger Bucket-Name und REGION die Region, in der Sie die Funktion bereitstellen möchten:

    gcloud storage buckets create gs://YOUR_INPUT_BUCKET_NAME --location=REGION
  2. Erstellen Sie einen regionalen Cloud Storage-Bucket, um unkenntlich gemachte Bilder zu erhalten, wobei YOUR_OUTPUT_BUCKET_NAME ein global eindeutiger Bucket-Name ist und REGION die Region ist, in der Sie die Funktion bereitstellen möchten:

    gcloud storage buckets create gs://YOUR_OUTPUT_BUCKET_NAME --location=REGION
  3. Klonen Sie das Repository der Beispiel-App auf Ihren lokalen Computer:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

  4. Wechseln Sie in das Verzeichnis, das den Beispielcode für Cloud Run Functions enthält:

    Node.js

    cd nodejs-docs-samples/functions/v2/imagemagick/

    Python

    cd python-docs-samples/functions/v2/imagemagick/

    Go

    cd golang-samples/functions/functionsv2/imagemagick/

    Java

    cd java-docs-samples/functions/v2/imagemagick/

Den Code verstehen

Das ImageMagick-Beispiel enthält Abhängigkeiten und zwei verschiedene Funktionen. Die erste Funktion analysiert das Bild und die zweite Funktion macht es unkenntlich, wenn es gewalttätige Inhalte oder Inhalte nur für Erwachsene enthält.

Abhängigkeiten importieren

Die Anwendung muss mehrere Abhängigkeiten importieren, um mit Google Cloud-Diensten, ImageMagick und dem Dateisystem zu kommunizieren:

ImageMagick und das zugehörige convert-Befehlszeilentool sind für die meisten Laufzeiten standardmäßig in der Ausführungsumgebung von Cloud Run-Funktionen enthalten. Für PHP müssen Sie möglicherweise eine manuelle Konfiguration vornehmen. Beachten Sie, dass Cloud Run-Funktionen keine Installation benutzerdefinierter Pakete auf Systemebene unterstützt.

Node.js

const functions = require('@google-cloud/functions-framework');
const gm = require('gm').subClass({imageMagick: true});
const fs = require('fs').promises;
const path = require('path');
const vision = require('@google-cloud/vision');

const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const client = new vision.ImageAnnotatorClient();

const {BLURRED_BUCKET_NAME} = process.env;

Python

import os
import tempfile

import functions_framework
from google.cloud import storage, vision
from wand.image import Image

storage_client = storage.Client()
vision_client = vision.ImageAnnotatorClient()

Go


// Package imagemagick contains an example of using ImageMagick to process a
// file uploaded to Cloud Storage.
package imagemagick

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"os/exec"

	"cloud.google.com/go/storage"
	vision "cloud.google.com/go/vision/apiv1"
	"cloud.google.com/go/vision/v2/apiv1/visionpb"
	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	cloudevents "github.com/cloudevents/sdk-go/v2"
	"github.com/googleapis/google-cloudevents-go/cloud/storagedata"
	"google.golang.org/protobuf/encoding/protojson"
)

// Global API clients used across function invocations.
var (
	storageClient *storage.Client
	visionClient  *vision.ImageAnnotatorClient
)

func init() {
	// Declare a separate err variable to avoid shadowing the client variables.
	var err error

	bgctx := context.Background()
	storageClient, err = storage.NewClient(bgctx)
	if err != nil {
		log.Fatalf("storage.NewClient: %v", err)
	}

	visionClient, err = vision.NewImageAnnotatorClient(bgctx)
	if err != nil {
		log.Fatalf("vision.NewAnnotatorClient: %v", err)
	}
	functions.CloudEvent("blur-offensive-images", blurOffensiveImages)
}

Java


import com.google.cloud.functions.CloudEventsFunction;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import com.google.cloud.vision.v1.AnnotateImageRequest;
import com.google.cloud.vision.v1.AnnotateImageResponse;
import com.google.cloud.vision.v1.BatchAnnotateImagesResponse;
import com.google.cloud.vision.v1.Feature;
import com.google.cloud.vision.v1.Feature.Type;
import com.google.cloud.vision.v1.Image;
import com.google.cloud.vision.v1.ImageAnnotatorClient;
import com.google.cloud.vision.v1.ImageSource;
import com.google.cloud.vision.v1.SafeSearchAnnotation;
import com.google.events.cloud.storage.v1.StorageObjectData;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import io.cloudevents.CloudEvent;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ImageMagick implements CloudEventsFunction {

  private static Storage storage = StorageOptions.getDefaultInstance().getService();
  private static final String BLURRED_BUCKET_NAME = System.getenv("BLURRED_BUCKET_NAME");
  private static final Logger logger = Logger.getLogger(ImageMagick.class.getName());
}

Bilder analysieren

Die folgende Funktion wird aufgerufen, wenn ein Bild in den Cloud Storage-Bucket hochgeladen wird, den Sie für Bildereingaben erstellt haben. Die Funktion verwendet die Vision API, um gewaltverherrlichende oder nicht jugendfreie Inhalte in hochgeladenen Bildern zu erkennen.

Node.js

// Blurs uploaded images that are flagged as Adult or Violence.
functions.cloudEvent('blurOffensiveImages', async cloudEvent => {
  // This event represents the triggering Cloud Storage object.
  const bucket = cloudEvent.data.bucket;
  const name = cloudEvent.data.name;
  const file = storage.bucket(bucket).file(name);
  const filePath = `gs://${bucket}/${name}`;

  console.log(`Analyzing ${file.name}.`);

  try {
    const [result] = await client.safeSearchDetection(filePath);
    const detections = result.safeSearchAnnotation || {};

    if (
      // Levels are defined in https://cloud.google.com/vision/docs/reference/rest/v1/AnnotateImageResponse#likelihood
      detections.adult === 'VERY_LIKELY' ||
      detections.violence === 'VERY_LIKELY'
    ) {
      console.log(`Detected ${file.name} as inappropriate.`);
      return await blurImage(file, BLURRED_BUCKET_NAME);
    } else {
      console.log(`Detected ${file.name} as OK.`);
    }
  } catch (err) {
    console.error(`Failed to analyze ${file.name}.`, err);
    throw err;
  }
});

Python

# Blurs uploaded images that are flagged as Adult or Violent imagery.
@functions_framework.cloud_event
def blur_offensive_images(cloud_event):
    file_data = cloud_event.data

    file_name = file_data["name"]
    bucket_name = file_data["bucket"]

    blob = storage_client.bucket(bucket_name).get_blob(file_name)
    blob_uri = f"gs://{bucket_name}/{file_name}"
    blob_source = vision.Image(source=vision.ImageSource(gcs_image_uri=blob_uri))

    # Ignore already-blurred files
    if file_name.startswith("blurred-"):
        print(f"The image {file_name} is already blurred.")
        return

    print(f"Analyzing {file_name}.")

    result = vision_client.safe_search_detection(image=blob_source)
    detected = result.safe_search_annotation

    # Process image
    # 5 maps to VERY_LIKELY
    if detected.adult == 5 or detected.violence == 5:
        print(f"The image {file_name} was detected as inappropriate.")
        return __blur_image(blob)
    else:
        print(f"The image {file_name} was detected as OK.")

Go


// blurOffensiveImages blurs offensive images uploaded to GCS.
func blurOffensiveImages(ctx context.Context, e cloudevents.Event) error {
	outputBucket := os.Getenv("BLURRED_BUCKET_NAME")
	if outputBucket == "" {
		return errors.New("environment variable BLURRED_BUCKET_NAME must be set")
	}

	var gcsEvent storagedata.StorageObjectData
	if err := protojson.Unmarshal(e.Data(), &gcsEvent); err != nil {
		return fmt.Errorf("protojson.Unmarshal: failed to decode event data: %w", err)
	}
	img := vision.NewImageFromURI(fmt.Sprintf("gs://%s/%s", gcsEvent.GetBucket(), gcsEvent.GetName()))

	resp, err := visionClient.DetectSafeSearch(ctx, img, nil)
	if err != nil {
		return fmt.Errorf("visionClient.DetectSafeSearch: %w", err)
	}

	if resp.GetAdult() == visionpb.Likelihood_VERY_LIKELY ||
		resp.GetViolence() == visionpb.Likelihood_VERY_LIKELY {
		return blur(ctx, gcsEvent.Bucket, outputBucket, gcsEvent.Name)
	}
	log.Printf("The image %q was detected as OK.", gcsEvent.Name)
	return nil
}

Java

@Override
// Blurs uploaded images that are flagged as Adult or Violence.
public void accept(CloudEvent event) throws InvalidProtocolBufferException {
  // Extract the GCS Event data from the CloudEvent's data payload.
  StorageObjectData data = getEventData(event);
  // Validate parameters
  if (data == null) {
    logger.severe("Error: Malformed GCS event.");
    return;
  }

  BlobInfo blobInfo = BlobInfo.newBuilder(data.getBucket(), data.getName()).build();

  // Construct URI to GCS bucket and file.
  String gcsPath = String.format("gs://%s/%s", data.getBucket(), data.getName());
  logger.info(String.format("Analyzing %s", data.getName()));

  // Construct request.
  ImageSource imgSource = ImageSource.newBuilder().setImageUri(gcsPath).build();
  Image img = Image.newBuilder().setSource(imgSource).build();
  Feature feature = Feature.newBuilder().setType(Type.SAFE_SEARCH_DETECTION).build();
  AnnotateImageRequest request = AnnotateImageRequest
      .newBuilder()
      .addFeatures(feature)
      .setImage(img)
      .build();
  List<AnnotateImageRequest> requests = List.of(request);

  // Send request to the Vision API.
  try (ImageAnnotatorClient client = ImageAnnotatorClient.create()) {
    BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests);
    List<AnnotateImageResponse> responses = response.getResponsesList();
    for (AnnotateImageResponse res : responses) {
      if (res.hasError()) {
        logger.info(String.format("Error: %s", res.getError().getMessage()));
        return;
      }
      // Get Safe Search Annotations
      SafeSearchAnnotation annotation = res.getSafeSearchAnnotation();
      if (annotation.getAdultValue() == 5 || annotation.getViolenceValue() == 5) {
        logger.info(String.format("Detected %s as inappropriate.", data.getName()));
        blur(blobInfo);
      } else {
        logger.info(String.format("Detected %s as OK.", data.getName()));
      }
    }
  } catch (IOException e) {
    logger.log(Level.SEVERE, "Error with Vision API: " + e.getMessage(), e);
  }
}

Bilder unkenntlich machen

Die folgende Funktion wird aufgerufen, wenn in einem hochgeladenen Bild gewaltverherrlichende oder nicht jugendfreie Inhalte erkannt werden. Die Funktion lädt das anstößige Bild herunter, macht das Bild mit ImageMagick unkenntlich und lädt das bearbeitete Bild dann hoch in Ihren Ausgabebucket.

Node.js

// Blurs the given file using ImageMagick, and uploads it to another bucket.
const blurImage = async (file, blurredBucketName) => {
  const tempLocalPath = `/tmp/${path.parse(file.name).base}`;

  // Download file from bucket.
  try {
    await file.download({destination: tempLocalPath});

    console.log(`Downloaded ${file.name} to ${tempLocalPath}.`);
  } catch (err) {
    throw new Error(`File download failed: ${err}`);
  }

  await new Promise((resolve, reject) => {
    gm(tempLocalPath)
      .blur(0, 16)
      .write(tempLocalPath, (err, stdout) => {
        if (err) {
          console.error('Failed to blur image.', err);
          reject(err);
        } else {
          console.log(`Blurred image: ${file.name}`);
          resolve(stdout);
        }
      });
  });

  // Upload result to a different bucket, to avoid re-triggering this function.
  const blurredBucket = storage.bucket(blurredBucketName);

  // Upload the Blurred image back into the bucket.
  const gcsPath = `gs://${blurredBucketName}/${file.name}`;
  try {
    await blurredBucket.upload(tempLocalPath, {destination: file.name});
    console.log(`Uploaded blurred image to: ${gcsPath}`);
  } catch (err) {
    throw new Error(`Unable to upload blurred image to ${gcsPath}: ${err}`);
  }

  // Delete the temporary file.
  return fs.unlink(tempLocalPath);
};

Python

# Blurs the given file using ImageMagick.
def __blur_image(current_blob):
    file_name = current_blob.name
    _, temp_local_filename = tempfile.mkstemp()

    # Download file from bucket.
    current_blob.download_to_filename(temp_local_filename)
    print(f"Image {file_name} was downloaded to {temp_local_filename}.")

    # Blur the image using ImageMagick.
    with Image(filename=temp_local_filename) as image:
        image.resize(*image.size, blur=16, filter="hamming")
        image.save(filename=temp_local_filename)

    print(f"Image {file_name} was blurred.")

    # Upload result to a second bucket, to avoid re-triggering the function.
    # You could instead re-upload it to the same bucket + tell your function
    # to ignore files marked as blurred (e.g. those with a "blurred" prefix)
    blur_bucket_name = os.getenv("BLURRED_BUCKET_NAME")
    blur_bucket = storage_client.bucket(blur_bucket_name)
    new_blob = blur_bucket.blob(file_name)
    new_blob.upload_from_filename(temp_local_filename)
    print(f"Blurred image uploaded to: gs://{blur_bucket_name}/{file_name}")

    # Delete the temporary file.
    os.remove(temp_local_filename)

Go


// blur blurs the image stored at gs://inputBucket/name and stores the result in
// gs://outputBucket/name.
func blur(ctx context.Context, inputBucket, outputBucket, name string) error {
	inputBlob := storageClient.Bucket(inputBucket).Object(name)
	r, err := inputBlob.NewReader(ctx)
	if err != nil {
		return fmt.Errorf("inputBlob.NewReader: %w", err)
	}

	outputBlob := storageClient.Bucket(outputBucket).Object(name)
	w := outputBlob.NewWriter(ctx)
	defer w.Close()

	// Use - as input and output to use stdin and stdout.
	cmd := exec.Command("convert", "-", "-blur", "0x8", "-")
	cmd.Stdin = r
	cmd.Stdout = w

	if err := cmd.Run(); err != nil {
		return fmt.Errorf("cmd.Run: %w", err)
	}

	if err := w.Close(); err != nil {
		return fmt.Errorf("failed to write output file: %w", err)
	}
	log.Printf("Blurred image uploaded to gs://%s/%s", outputBlob.BucketName(), outputBlob.ObjectName())

	return nil
}

Java

// Blurs the file described by blobInfo using ImageMagick,
// and uploads it to the blurred bucket.
private static void blur(BlobInfo blobInfo) throws IOException {
  String bucketName = blobInfo.getBucket();
  String fileName = blobInfo.getName();

  // Download image
  Blob blob = storage.get(BlobId.of(bucketName, fileName));
  Path download = Paths.get("/tmp/", fileName);
  blob.downloadTo(download);

  // Construct the command.
  Path upload = Paths.get("/tmp/", "blurred-" + fileName);
  List<String> args = List.of("convert", download.toString(), "-blur", "0x8", upload.toString());
  try {
    ProcessBuilder pb = new ProcessBuilder(args);
    Process process = pb.start();
    process.waitFor();
  } catch (Exception e) {
    logger.info(String.format("Error: %s", e.getMessage()));
  }

  // Upload image to blurred bucket.
  BlobId blurredBlobId = BlobId.of(BLURRED_BUCKET_NAME, fileName);
  BlobInfo blurredBlobInfo = BlobInfo
      .newBuilder(blurredBlobId)
      .setContentType(blob.getContentType())
      .build();

  byte[] blurredFile = Files.readAllBytes(upload);
  storage.create(blurredBlobInfo, blurredFile);
  logger.info(
      String.format("Blurred image uploaded to: gs://%s/%s", BLURRED_BUCKET_NAME, fileName));

  // Remove images from fileSystem
  Files.delete(download);
  Files.delete(upload);
}

Funktion implementieren

Führen Sie den folgenden Befehl in dem Verzeichnis aus, das den Beispielcode (oder im Fall von Java die Datei pom.xml) enthält, um die Cloud Run-Funktion mit einem Speichertrigger bereitzustellen.

Node.js

gcloud functions deploy nodejs-blur-function \
--gen2 \
--runtime=RUNTIME \
--region=REGION \
--source=. \
--entry-point=blurOffensiveImages \
--trigger-bucket=YOUR_INPUT_BUCKET_NAME \
--set-env-vars=BLURRED_BUCKET_NAME=YOUR_OUTPUT_BUCKET_NAME

Python

gcloud functions deploy python-blur-function \
--gen2 \
--runtime=RUNTIME \
--region=REGION \
--source=. \
--entry-point=blur_offensive_images \
--trigger-bucket=YOUR_INPUT_BUCKET_NAME \
--set-env-vars=BLURRED_BUCKET_NAME=YOUR_OUTPUT_BUCKET_NAME

Go

gcloud functions deploy go-blur-function \
--gen2 \
--runtime=RUNTIME \
--region=REGION \
--source=. \
--entry-point=blur-offensive-images \
--trigger-bucket=YOUR_INPUT_BUCKET_NAME \
--set-env-vars=BLURRED_BUCKET_NAME=YOUR_OUTPUT_BUCKET_NAME

Java

gcloud functions deploy java-blur-function \
--gen2 \
--runtime=RUNTIME \
--region=REGION \
--source=. \
--entry-point=functions.ImageMagick \
--trigger-bucket=YOUR_INPUT_BUCKET_NAME \
--set-env-vars=BLURRED_BUCKET_NAME=YOUR_OUTPUT_BUCKET_NAME

Ersetzen Sie dabei Folgendes:

  • RUNTIME: eine Laufzeit, die auf Ubuntu 18.04 oder höher basiert
  • REGION: Der Name der Google Cloud-Region, in der Sie die Funktion bereitstellen möchten (z. B. us-west1).
  • YOUR_INPUT_BUCKET_NAME: Der Name des Cloud Storage-Buckets zum Hochladen von Bildern.
  • YOUR_OUTPUT_BUCKET_NAME: Der Name des Buckets, in dem die unkenntlich gemachten Bilder gespeichert werden sollen.

Geben Sie beim Bereitstellen von Cloud Run-Funktionen nur den Bucket-Namen ohne das führende gs:// an, z. B. --trigger-event-filters="bucket=my-bucket".

Bild hochladen

  1. Laden Sie ein anstößiges Bild hoch, z. B. dieses Bild eines blutrünstigen Zombies:

    gcloud storage cp zombie.jpg gs://YOUR_INPUT_BUCKET_NAME

    Dabei ist YOUR_INPUT_BUCKET_NAME der Cloud Storage-Bucket, den Sie zuvor zum Hochladen von Bildern erstellt haben.

  2. Die Analyse des Bildes sollte in den Logs angezeigt werden:

    gcloud beta functions logs read YOUR_FUNCTION_NAME --gen2 --limit=100
  3. Sie können sich die unkenntlich gemachten Bilder im Cloud Storage-Bucket YOUR_OUTPUT_BUCKET_NAME ansehen, den Sie zuvor erstellt haben.

Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten durch Löschen des für die Anleitung erstellten Projekts.

So löschen Sie das Projekt:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Cloud Run-Funktion löschen

Durch das Löschen von Cloud Run-Funktionen werden keine in Cloud Storage gespeicherten Ressourcen entfernt.

Führen Sie den folgenden Befehl aus, um die in dieser Anleitung bereitgestellte Funktion zu löschen:

Node.js

gcloud functions delete nodejs-blur-function --gen2 --region REGION 

Python

gcloud functions delete python-blur-function --gen2 --region REGION 

Go

gcloud functions delete go-blur-function --gen2 --region REGION 

Java

gcloud functions delete java-blur-function --gen2 --region REGION 

Sie können Cloud Run-Funktionen auch über die Google Cloud Console löschen.