Google Cloud Vision API と ImageMagick を使用して、Cloud Storage バケットにアップロードされた不適切な画像を検出してぼかす方法を示します。
もっと見る
このコードサンプルを含む詳細なドキュメントについては、以下をご覧ください。
コードサンプル
C#
/// <summary>
/// Downloads the Storage object specified by <paramref name="data"/>,
/// blurs it using ImageMagick, and uploads it to the "blurred" bucket.
/// </summary>
private async Task BlurImageAsync(StorageObjectData data, CancellationToken cancellationToken)
{
// Download image
string originalImageFile = Path.GetTempFileName();
using (Stream output = File.Create(originalImageFile))
{
await _storageClient.DownloadObjectAsync(data.Bucket, data.Name, output, cancellationToken: cancellationToken);
}
// Construct the ImageMagick command
string blurredImageFile = Path.GetTempFileName();
// Command-line arguments for ImageMagick.
// Paths are wrapped in quotes in case they contain spaces.
string arguments = $"\"{originalImageFile}\" -blur 0x8, \"{blurredImageFile}\"";
// Run the ImageMagick command line tool ("convert").
Process process = Process.Start("convert", arguments);
// Process doesn't expose a way of asynchronously waiting for completion.
// See https://stackoverflow.com/questions/470256 for examples of how
// this can be achieved using events, but for the sake of brevity,
// this sample just waits synchronously.
process.WaitForExit();
// If ImageMagick failed, log the error but complete normally to avoid retrying.
if (process.ExitCode != 0)
{
_logger.LogError("ImageMagick exited with code {exitCode}", process.ExitCode);
return;
}
// Upload image to blurred bucket.
using (Stream input = File.OpenRead(blurredImageFile))
{
await _storageClient.UploadObjectAsync(
s_blurredBucketName, data.Name, data.ContentType, input, cancellationToken: cancellationToken);
}
string uri = $"gs://{s_blurredBucketName}/{data.Name}";
_logger.LogInformation("Blurred image uploaded to: {uri}", uri);
// Remove images from the file system.
File.Delete(originalImageFile);
File.Delete(blurredImageFile);
}
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: %v", 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: %v", err)
}
if err := w.Close(); err != nil {
return fmt.Errorf("failed to write output file: %v", 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);
}
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);
};
PHP
// Blurs the given file using ImageMagick, and uploads it to another bucket.
function blurImage(
$log,
Object $file,
string $blurredBucketName
): void {
$tempLocalPath = sys_get_temp_dir() . '/' . $file->name();
// Download file from bucket.
$image = new Imagick();
try {
$image->readImageBlob($file->downloadAsStream());
} catch (Exception $e) {
throw new Exception('Streaming download failed: ' . $e);
}
// Blur file using ImageMagick
// (The Imagick class is from the PECL 'imagick' package)
$image->blurImage(0, 16);
// Stream blurred image result to a different bucket. // (This avoids re-triggering this function.)
$storage = new StorageClient();
$blurredBucket = $storage->bucket($blurredBucketName);
// Upload the Blurred image back into the bucket.
$gcsPath = 'gs://' . $blurredBucketName . '/' . $file->name();
try {
$blurredBucket->upload($image->getImageBlob(), [
'name' => $file->name()
]);
fwrite($log, 'Streamed blurred image to: ' . $gcsPath . PHP_EOL);
} catch (Exception $e) {
throw new Exception(
sprintf(
'Unable to stream blurred image to %s: %s',
$gcsPath,
$e->getMessage()
)
);
}
}
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)
Ruby
require "tempfile"
require "mini_magick"
# Blurs the given file using ImageMagick.
def blur_image bucket_name, file_name
tempfile = Tempfile.new
begin
# Download the image file
bucket = global(:storage_client).bucket bucket_name
file = bucket.file file_name
file.download tempfile
tempfile.close
# Blur the image using ImageMagick
MiniMagick::Image.new tempfile.path do |image|
image.blur "0x16"
end
logger.info "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 and tell your function
# to ignore files marked as blurred (e.g. those with a "blurred" prefix.)
blur_bucket_name = ENV["BLURRED_BUCKET_NAME"]
blur_bucket = global(:storage_client).bucket blur_bucket_name
blur_bucket.create_file tempfile.path, file_name
logger.info "Blurred image uploaded to gs://#{blur_bucket_name}/#{file_name}"
ensure
# Ruby will remove the temp file when garbage collecting the object,
# but it is good practice to remove it explicitly.
tempfile.unlink
end
end
次のステップ
他の Google Cloud プロダクトに関連するコードサンプルの検索およびフィルタ検索を行うには、Google Cloud のサンプルをご覧ください。