1. بررسی اجمالی
در اولین آزمایشگاه کد، تصاویر را در یک سطل آپلود خواهید کرد. این یک رویداد ایجاد فایل ایجاد می کند که توسط یک تابع مدیریت می شود. این تابع با Vision API تماس می گیرد تا تجزیه و تحلیل تصویر را انجام دهد و نتایج را در یک دیتا استور ذخیره کند.
چیزی که یاد خواهید گرفت
- فضای ذخیره سازی ابری
- توابع ابری
- Cloud Vision API
- Cloud Firestore
2. راه اندازی و الزامات
تنظیم محیط خود به خود
- به Google Cloud Console وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. اگر قبلاً یک حساب Gmail یا Google Workspace ندارید، باید یک حساب ایجاد کنید .
- نام پروژه نام نمایشی برای شرکت کنندگان این پروژه است. این یک رشته کاراکتری است که توسط API های Google استفاده نمی شود. شما می توانید آن را در هر زمان به روز کنید.
- شناسه پروژه باید در تمام پروژههای Google Cloud منحصربهفرد باشد و تغییرناپذیر باشد (پس از تنظیم نمیتوان آن را تغییر داد). Cloud Console به طور خودکار یک رشته منحصر به فرد تولید می کند. معمولاً برای شما مهم نیست که چیست. در اکثر کدها، باید به شناسه پروژه ارجاع دهید (معمولاً به عنوان
PROJECT_ID
شناخته می شود). اگر شناسه تولید شده را دوست ندارید، ممکن است یک شناسه تصادفی دیگر ایجاد کنید. از طرف دیگر، میتوانید خودتان را امتحان کنید و ببینید آیا در دسترس است یا خیر. پس از این مرحله نمی توان آن را تغییر داد و در طول مدت پروژه باقی می ماند. - برای اطلاع شما، یک مقدار سوم وجود دارد، یک شماره پروژه که برخی از API ها از آن استفاده می کنند. در مورد هر سه این مقادیر در مستندات بیشتر بیاموزید.
- در مرحله بعد، برای استفاده از منابع Cloud/APIها باید صورتحساب را در کنسول Cloud فعال کنید . اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. برای اینکه منابع را خاموش کنید تا بیش از این آموزش متحمل صورتحساب نشوید، می توانید منابعی را که ایجاد کرده اید حذف کنید یا کل پروژه را حذف کنید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.
Cloud Shell را راه اندازی کنید
در حالی که Google Cloud را می توان از راه دور از لپ تاپ شما کار کرد، در این کد لبه از Google Cloud Shell استفاده خواهید کرد، یک محیط خط فرمان که در Cloud اجرا می شود.
از Google Cloud Console ، روی نماد Cloud Shell در نوار ابزار بالا سمت راست کلیک کنید:
تهیه و اتصال به محیط فقط چند لحظه طول می کشد. وقتی تمام شد، باید چیزی شبیه به این را ببینید:
این ماشین مجازی با تمام ابزارهای توسعه که شما نیاز دارید بارگذاری شده است. این یک فهرست اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد و احراز هویت شبکه را تا حد زیادی افزایش می دهد. تمام کارهای شما در این کد لبه را می توان در یک مرورگر انجام داد. شما نیازی به نصب چیزی ندارید.
3. API ها را فعال کنید
برای این آزمایشگاه، از Cloud Functions و Vision API استفاده خواهید کرد، اما ابتدا باید آنها را یا در Cloud Console یا با gcloud
فعال کنید.
برای فعال کردن Vision API در Cloud Console، Cloud Vision API
را در نوار جستجو جستجو کنید:
شما در صفحه Cloud Vision API قرار خواهید گرفت:
روی دکمه ENABLE
کلیک کنید.
همچنین میتوانید با استفاده از ابزار خط فرمان gcloud آن را فعال کنید.
در داخل Cloud Shell، دستور زیر را اجرا کنید:
gcloud services enable vision.googleapis.com
برای اتمام موفقیت آمیز باید عملیات را مشاهده کنید:
Operation "operations/acf.12dba18b-106f-4fd2-942d-fea80ecc5c1c" finished successfully.
عملکردهای ابری را نیز فعال کنید:
gcloud services enable cloudfunctions.googleapis.com
4. ایجاد سطل (کنسول)
یک سطل ذخیره سازی برای تصاویر ایجاد کنید. می توانید این کار را از کنسول Google Cloud Platform ( consol.cloud.google.com ) یا با ابزار خط فرمان gsutil از Cloud Shell یا محیط توسعه محلی خود انجام دهید.
به Storage بروید
از منوی "همبرگر" (☰)، به صفحه Storage
بروید.
سطل خود را نام ببرید
روی دکمه CREATE BUCKET
کلیک کنید.
CONTINUE
کلیک کنید.
مکان را انتخاب کنید
یک سطل چند منطقه ای در منطقه مورد نظر خود ایجاد کنید (اینجا Europe
).
CONTINUE
کلیک کنید.
کلاس ذخیره سازی پیش فرض را انتخاب کنید
کلاس ذخیره سازی Standard
را برای داده های خود انتخاب کنید.
CONTINUE
کلیک کنید.
کنترل دسترسی را تنظیم کنید
از آنجایی که با تصاویر در دسترس عموم کار می کنید، می خواهید همه تصاویر ذخیره شده ما در این سطل کنترل دسترسی یکسانی داشته باشند.
گزینه Uniform
Access Control را انتخاب کنید.
CONTINUE
کلیک کنید.
حفاظت/رمزگذاری را تنظیم کنید
پیش فرض ( Google-managed key)
را حفظ کنید، زیرا از کلیدهای رمزگذاری خود استفاده نخواهید کرد.
روی CREATE
کلیک کنید تا در نهایت ایجاد سطل ما نهایی شود.
allUsers را به عنوان نمایشگر ذخیره سازی اضافه کنید
به برگه Permissions
بروید:
یک عضو allUsers
را با نقش Storage > Storage Object Viewer
به سطل اضافه کنید:
روی SAVE
کلیک کنید.
5. سطل (gsutil) را ایجاد کنید
همچنین می توانید از ابزار خط فرمان gsutil
در Cloud Shell برای ایجاد سطل استفاده کنید.
در Cloud Shell، یک متغیر برای نام سطل یکتا تنظیم کنید. Cloud Shell قبلاً GOOGLE_CLOUD_PROJECT
را روی شناسه پروژه منحصر به فرد شما تنظیم کرده است. می توانید آن را به نام سطل اضافه کنید.
به عنوان مثال:
export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
ایجاد یک منطقه استاندارد چند منطقه ای در اروپا:
gsutil mb -l EU gs://${BUCKET_PICTURES}
از دسترسی یکنواخت به سطح سطل اطمینان حاصل کنید:
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
سطل را عمومی کنید:
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}
اگر به بخش Cloud Storage
کنسول بروید، باید یک سطل uploaded-pictures
عمومی داشته باشید:
تست کنید که می توانید تصاویر را در سطل آپلود کنید و تصاویر آپلود شده برای عموم در دسترس هستند، همانطور که در مرحله قبل توضیح داده شد.
6. دسترسی عمومی به سطل را آزمایش کنید
با بازگشت به مرورگر ذخیره سازی، سطل خود را با دسترسی «عمومی» (شامل یک علامت هشدار که به شما یادآوری می کند که هر کسی به محتوای آن سطل دسترسی دارد) را در لیست می بینید.
اکنون سطل شما برای دریافت تصاویر آماده است.
اگر روی نام سطل کلیک کنید، جزئیات سطل را مشاهده خواهید کرد.
در آنجا، میتوانید دکمه Upload files
را امتحان کنید تا آزمایش کنید که میتوانید تصویری را به سطل اضافه کنید. یک پنجره انتخابگر فایل از شما می خواهد که یک فایل را انتخاب کنید. پس از انتخاب، در سطل شما آپلود می شود و دوباره دسترسی public
را که به طور خودکار به این فایل جدید نسبت داده شده است، خواهید دید.
در کنار برچسب دسترسی Public
، نماد پیوند کوچکی را نیز مشاهده خواهید کرد. وقتی روی آن کلیک می کنید، مرورگر شما به آدرس عمومی آن تصویر می رود که به شکل زیر خواهد بود:
https://storage.googleapis.com/BUCKET_NAME/PICTURE_FILE.png
با BUCKET_NAME
نام منحصربهفرد جهانی است که برای سطل خود انتخاب کردهاید، و سپس نام فایل تصویرتان.
با کلیک بر روی کادر کنار نام تصویر، دکمه DELETE
فعال می شود و می توانید این تصویر اول را حذف کنید.
7. تابع را ایجاد کنید
در این مرحله، تابعی ایجاد می کنید که به رویدادهای آپلود عکس واکنش نشان می دهد.
از بخش Cloud Functions
کنسول Google Cloud دیدن کنید. با مراجعه به آن سرویس Cloud Functions به صورت خودکار فعال می شود.
روی Create function
کلیک کنید.
یک نام (مثلاً picture-uploaded
) و منطقه (به یاد داشته باشید که با انتخاب منطقه برای سطل مطابقت داشته باشد) انتخاب کنید:
دو نوع عملکرد وجود دارد:
- توابع HTTP که می توانند از طریق URL (به عنوان مثال یک وب API) فراخوانی شوند.
- توابع پسزمینه که میتوانند توسط برخی رویدادها فعال شوند.
میخواهید یک تابع پسزمینه ایجاد کنید که هنگام آپلود یک فایل جدید در سطل Cloud Storage
ما فعال شود:
شما به نوع رویداد Finalize/Create
علاقه مند هستید، که رویدادی است که هنگام ایجاد یا به روز رسانی یک فایل در سطل فعال می شود:
سطل ایجاد شده قبلی را انتخاب کنید تا به Cloud Function ها بگویید که هنگام ایجاد / به روز رسانی فایل در این سطل خاص مطلع شوند:
برای انتخاب سطلی که قبلا ایجاد کرده اید، روی Select
کلیک کنید و سپس Save
انتخاب کنید
قبل از اینکه روی Next کلیک کنید، میتوانید پیشفرضها (حافظه 256 مگابایتی) را در قسمت Runtime، ساخت، اتصالات و تنظیمات امنیتی گسترش و تغییر دهید و آن را به 1 گیگابایت بهروزرسانی کنید.
پس از کلیک بر روی Next
، می توانید زمان اجرا ، کد منبع و نقطه ورودی را تنظیم کنید.
Inline editor
برای این تابع نگه دارید:
یکی از زمان های اجرا جاوا را انتخاب کنید، به عنوان مثال جاوا 11:
کد منبع شامل یک فایل Java
و یک فایل pom.xml
Maven است که متادیتا و وابستگی های مختلفی را ارائه می دهد.
قطعه پیشفرض کد را بگذارید: نام فایل تصویر آپلود شده را ثبت میکند:
در حال حاضر، برای اهداف آزمایشی، نام تابع را برای اجرا در Example
نگه دارید.
برای ایجاد و استقرار تابع بر روی Deploy
کلیک کنید. هنگامی که استقرار با موفقیت انجام شد، باید یک علامت دایره سبز در لیست توابع مشاهده کنید:
8. تابع را تست کنید
در این مرحله تست کنید که تابع به رویدادهای ذخیره سازی پاسخ می دهد.
از منوی "همبرگر" (☰)، به صفحه Storage
برگردید.
روی سطل تصاویر کلیک کنید و سپس بر روی Upload files
کلیک کنید تا یک تصویر آپلود شود.
دوباره در کنسول ابری حرکت کنید تا به صفحه Logging > Logs Explorer
بروید.
در انتخابگر Log Fields
، Cloud Function
انتخاب کنید تا گزارش های اختصاص داده شده به عملکردهای خود را ببینید. در قسمت Log Fields به پایین اسکرول کنید و حتی می توانید یک تابع خاص را انتخاب کنید تا نمای دقیق تری از گزارش های مربوط به توابع داشته باشید. عملکرد picture-uploaded
انتخاب کنید.
شما باید موارد گزارش را مشاهده کنید که به ایجاد تابع، زمان شروع و پایان تابع و بیانیه گزارش واقعی ما اشاره می کند:
بیانیه گزارش ما چنین میگوید: Processing file: pic-a-daily-architecture-events.png
، به این معنی که رویداد مربوط به ایجاد و ذخیرهسازی این تصویر واقعاً همانطور که انتظار میرفت راهاندازی شده است.
9. پایگاه داده را آماده کنید
شما اطلاعات مربوط به تصویر ارائه شده توسط Vision API را در پایگاه داده Cloud Firestore ، یک پایگاه داده اسناد NoSQL سریع، کاملا مدیریت شده، بدون سرور و بومی ابری ذخیره خواهید کرد. با رفتن به بخش Firestore
در Cloud Console پایگاه داده خود را آماده کنید:
دو گزینه ارائه می شود: Native mode
یا Datastore mode
. از حالت بومی استفاده کنید، که ویژگیهای اضافی مانند پشتیبانی آفلاین و همگامسازی بلادرنگ را ارائه میدهد.
روی SELECT NATIVE MODE
کلیک کنید.
یک منطقه چندگانه (اینجا در اروپا، اما در حالت ایده آل حداقل همان منطقه ای که عملکرد و سطل ذخیره سازی شما هستند) انتخاب کنید.
روی دکمه CREATE DATABASE
کلیک کنید.
پس از ایجاد پایگاه داده، باید موارد زیر را مشاهده کنید:
با کلیک بر روی دکمه + START COLLECTION
یک مجموعه جدید ایجاد کنید.
pictures
مجموعه نام .
شما نیازی به ایجاد سند ندارید. وقتی تصاویر جدید در Cloud Storage ذخیره می شوند و توسط Vision API تجزیه و تحلیل می شوند، آنها را به صورت برنامه نویسی اضافه خواهید کرد.
روی Save
کلیک کنید.
Firestore اولین سند پیش فرض را در مجموعه جدید ایجاد می کند، می توانید با خیال راحت آن سند را حذف کنید زیرا حاوی اطلاعات مفیدی نیست:
اسنادی که به صورت برنامه نویسی در مجموعه ما ایجاد می شوند دارای 4 فیلد خواهند بود:
- نام (رشته): نام فایل تصویر آپلود شده که کلید سند نیز می باشد
- برچسب ها (آرایه رشته ها): برچسب های موارد شناسایی شده توسط Vision API
- رنگ (رشته): کد رنگ هگزادسیمال رنگ غالب (یعنی #ab12ef)
- ایجاد (تاریخ): مُهر زمانی ذخیره شدن فراداده این تصویر
- تصویر بندانگشتی (بولی): یک فیلد اختیاری که در صورت ایجاد یک تصویر کوچک برای این تصویر وجود دارد و درست است.
از آنجایی که در Firestore برای یافتن تصاویری که دارای ریز عکسها هستند جستجو میکنیم و بر اساس تاریخ ایجاد مرتب میکنیم، باید یک فهرست جستجو ایجاد کنیم.
می توانید با دستور زیر در Cloud Shell ایندکس را ایجاد کنید:
gcloud firestore indexes composite create \
--collection-group=pictures \
--field-config field-path=thumbnail,order=descending \
--field-config field-path=created,order=descending
یا میتوانید این کار را از کنسول Cloud انجام دهید، با کلیک بر روی Indexes
، در ستون پیمایش در سمت چپ، و سپس ایجاد یک نمایه ترکیبی مانند شکل زیر:
روی Create
کلیک کنید. ایجاد فهرست ممکن است چند دقیقه طول بکشد.
10. عملکرد را به روز کنید
به صفحه Functions
برگردید، برای به روز رسانی عملکرد برای فراخوانی Vision API برای تجزیه و تحلیل تصاویر و ذخیره ابرداده ها در Firestore.
از منوی "همبرگر" (☰)، به بخش Cloud Functions
بروید، روی نام تابع کلیک کنید، برگه Source
را انتخاب کنید و سپس روی دکمه EDIT
کلیک کنید.
ابتدا فایل pom.xml
را ویرایش کنید که وابستگی های تابع جاوا را فهرست می کند. برای افزودن وابستگی به Cloud Vision API Maven، کد را بهروزرسانی کنید:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cloudfunctions</groupId>
<artifactId>gcs-function</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>26.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>1.0.4</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-firestore</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-vision</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-storage</artifactId>
</dependency>
</dependencies>
<!-- Required for Java 11 functions in the inline editor -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<excludes>
<exclude>.google/</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
اکنون که وابستگی ها به روز هستند، با به روز رسانی فایل Example.java
با کد سفارشی ما، روی کد تابع ما کار می کنید.
ماوس را روی فایل Example.java
ببرید و روی مداد کلیک کنید. نام بسته و نام فایل را با src/main/java/fn/ImageAnalysis.java
جایگزین کنید.
کد زیر را جایگزین کد ImageAnalysis.java
کنید. در مرحله بعد توضیح داده خواهد شد.
package fn;
import com.google.cloud.functions.*;
import com.google.cloud.vision.v1.*;
import com.google.cloud.vision.v1.Feature.Type;
import com.google.cloud.firestore.*;
import com.google.api.core.ApiFuture;
import java.io.*;
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
import java.util.logging.Logger;
import fn.ImageAnalysis.GCSEvent;
public class ImageAnalysis implements BackgroundFunction<GCSEvent> {
private static final Logger logger = Logger.getLogger(ImageAnalysis.class.getName());
@Override
public void accept(GCSEvent event, Context context)
throws IOException, InterruptedException, ExecutionException {
String fileName = event.name;
String bucketName = event.bucket;
logger.info("New picture uploaded " + fileName);
try (ImageAnnotatorClient vision = ImageAnnotatorClient.create()) {
List<AnnotateImageRequest> requests = new ArrayList<>();
ImageSource imageSource = ImageSource.newBuilder()
.setGcsImageUri("gs://" + bucketName + "/" + fileName)
.build();
Image image = Image.newBuilder()
.setSource(imageSource)
.build();
Feature featureLabel = Feature.newBuilder()
.setType(Type.LABEL_DETECTION)
.build();
Feature featureImageProps = Feature.newBuilder()
.setType(Type.IMAGE_PROPERTIES)
.build();
Feature featureSafeSearch = Feature.newBuilder()
.setType(Type.SAFE_SEARCH_DETECTION)
.build();
AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
.addFeatures(featureLabel)
.addFeatures(featureImageProps)
.addFeatures(featureSafeSearch)
.setImage(image)
.build();
requests.add(request);
logger.info("Calling the Vision API...");
BatchAnnotateImagesResponse result = vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = result.getResponsesList();
if (responses.size() == 0) {
logger.info("No response received from Vision API.");
return;
}
AnnotateImageResponse response = responses.get(0);
if (response.hasError()) {
logger.info("Error: " + response.getError().getMessage());
return;
}
List<String> labels = response.getLabelAnnotationsList().stream()
.map(annotation -> annotation.getDescription())
.collect(Collectors.toList());
logger.info("Annotations found:");
for (String label: labels) {
logger.info("- " + label);
}
String mainColor = "#FFFFFF";
ImageProperties imgProps = response.getImagePropertiesAnnotation();
if (imgProps.hasDominantColors()) {
DominantColorsAnnotation colorsAnn = imgProps.getDominantColors();
ColorInfo colorInfo = colorsAnn.getColors(0);
mainColor = rgbHex(
colorInfo.getColor().getRed(),
colorInfo.getColor().getGreen(),
colorInfo.getColor().getBlue());
logger.info("Color: " + mainColor);
}
boolean isSafe = false;
if (response.hasSafeSearchAnnotation()) {
SafeSearchAnnotation safeSearch = response.getSafeSearchAnnotation();
isSafe = Stream.of(
safeSearch.getAdult(), safeSearch.getMedical(), safeSearch.getRacy(),
safeSearch.getSpoof(), safeSearch.getViolence())
.allMatch( likelihood ->
likelihood != Likelihood.LIKELY && likelihood != Likelihood.VERY_LIKELY
);
logger.info("Safe? " + isSafe);
}
// Saving result to Firestore
if (isSafe) {
FirestoreOptions firestoreOptions = FirestoreOptions.getDefaultInstance();
Firestore pictureStore = firestoreOptions.getService();
DocumentReference doc = pictureStore.collection("pictures").document(fileName);
Map<String, Object> data = new HashMap<>();
data.put("labels", labels);
data.put("color", mainColor);
data.put("created", new Date());
ApiFuture<WriteResult> writeResult = doc.set(data, SetOptions.merge());
logger.info("Picture metadata saved in Firestore at " + writeResult.get().getUpdateTime());
}
}
}
private static String rgbHex(float red, float green, float blue) {
return String.format("#%02x%02x%02x", (int)red, (int)green, (int)blue);
}
public static class GCSEvent {
String bucket;
String name;
}
}
11. تابع را کاوش کنید
بیایید نگاهی دقیق تر به بخش های مختلف جالب داشته باشیم.
ابتدا، ما وابستگی های خاص را در فایل Maven pom.xml
قرار می دهیم. Google Java Client Libraries برای حذف هرگونه تضاد وابستگی، یک Bill-of-Materials(BOM)
منتشر می کند. با استفاده از آن، لازم نیست نسخه ای را برای کتابخانه های مشتری Google اختصاص دهید
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>26.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
سپس، یک کلاینت برای Vision API آماده می کنیم:
...
try (ImageAnnotatorClient vision = ImageAnnotatorClient.create()) {
...
اکنون ساختار تابع ما می آید. ما از رویداد ورودی فیلدهایی را که به آنها علاقه مندیم می گیریم و آنها را به ساختار GCSEvent که تعریف می کنیم نگاشت می کنیم:
...
public class ImageAnalysis implements BackgroundFunction<GCSEvent> {
@Override
public void accept(GCSEvent event, Context context)
throws IOException, InterruptedException,
ExecutionException {
...
public static class GCSEvent {
String bucket;
String name;
}
به امضا، و همچنین نحوه بازیابی نام فایل و سطلی که عملکرد Cloud را راه اندازی کرده است، توجه کنید.
برای مرجع، در اینجا به چه صورت است payload رویداد:
{
"bucket":"uploaded-pictures",
"contentType":"image/png",
"crc32c":"efhgyA==",
"etag":"CKqB956MmucCEAE=",
"generation":"1579795336773802",
"id":"uploaded-pictures/Screenshot.png/1579795336773802",
"kind":"storage#object",
"md5Hash":"PN8Hukfrt6C7IyhZ8d3gfQ==",
"mediaLink":"https://www.googleapis.com/download/storage/v1/b/uploaded-pictures/o/Screenshot.png?generation=1579795336773802&alt=media",
"metageneration":"1",
"name":"Screenshot.png",
"selfLink":"https://www.googleapis.com/storage/v1/b/uploaded-pictures/o/Screenshot.png",
"size":"173557",
"storageClass":"STANDARD",
"timeCreated":"2020-01-23T16:02:16.773Z",
"timeStorageClassUpdated":"2020-01-23T16:02:16.773Z",
"updated":"2020-01-23T16:02:16.773Z"
}
ما درخواستی را برای ارسال از طریق مشتری Vision آماده می کنیم:
ImageSource imageSource = ImageSource.newBuilder()
.setGcsImageUri("gs://" + bucketName + "/" + fileName)
.build();
Image image = Image.newBuilder()
.setSource(imageSource)
.build();
Feature featureLabel = Feature.newBuilder()
.setType(Type.LABEL_DETECTION)
.build();
Feature featureImageProps = Feature.newBuilder()
.setType(Type.IMAGE_PROPERTIES)
.build();
Feature featureSafeSearch = Feature.newBuilder()
.setType(Type.SAFE_SEARCH_DETECTION)
.build();
AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
.addFeatures(featureLabel)
.addFeatures(featureImageProps)
.addFeatures(featureSafeSearch)
.setImage(image)
.build();
ما 3 قابلیت کلیدی Vision API را درخواست می کنیم:
- تشخیص برچسب : برای درک آنچه در آن تصاویر وجود دارد
- ویژگی های تصویر : برای دادن ویژگی های جالب به تصویر (ما به رنگ غالب تصویر علاقه مند هستیم)
- جستجوی ایمن : برای اطلاع از اینکه آیا تصویر برای نمایش بی خطر است (این تصویر نباید حاوی محتوای بزرگسالان / پزشکی / نژادی / خشونت آمیز باشد)
در این مرحله، میتوانیم با Vision API تماس بگیریم:
...
logger.info("Calling the Vision API...");
BatchAnnotateImagesResponse result =
vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = result.getResponsesList();
...
برای مرجع، در اینجا پاسخ از Vision API به نظر می رسد:
{
"faceAnnotations": [],
"landmarkAnnotations": [],
"logoAnnotations": [],
"labelAnnotations": [
{
"locations": [],
"properties": [],
"mid": "/m/01yrx",
"locale": "",
"description": "Cat",
"score": 0.9959855675697327,
"confidence": 0,
"topicality": 0.9959855675697327,
"boundingPoly": null
},
✄ - - - ✄
],
"textAnnotations": [],
"localizedObjectAnnotations": [],
"safeSearchAnnotation": {
"adult": "VERY_UNLIKELY",
"spoof": "UNLIKELY",
"medical": "VERY_UNLIKELY",
"violence": "VERY_UNLIKELY",
"racy": "VERY_UNLIKELY",
"adultConfidence": 0,
"spoofConfidence": 0,
"medicalConfidence": 0,
"violenceConfidence": 0,
"racyConfidence": 0,
"nsfwConfidence": 0
},
"imagePropertiesAnnotation": {
"dominantColors": {
"colors": [
{
"color": {
"red": 203,
"green": 201,
"blue": 201,
"alpha": null
},
"score": 0.4175916016101837,
"pixelFraction": 0.44456374645233154
},
✄ - - - ✄
]
}
},
"error": null,
"cropHintsAnnotation": {
"cropHints": [
{
"boundingPoly": {
"vertices": [
{ "x": 0, "y": 118 },
{ "x": 1177, "y": 118 },
{ "x": 1177, "y": 783 },
{ "x": 0, "y": 783 }
],
"normalizedVertices": []
},
"confidence": 0.41695669293403625,
"importanceFraction": 1
}
]
},
"fullTextAnnotation": null,
"webDetection": null,
"productSearchResults": null,
"context": null
}
اگر خطایی برگردانده نشد، میتوانیم ادامه دهیم، به همین دلیل این بلوک را داریم:
AnnotateImageResponse response = responses.get(0);
if (response.hasError()) {
logger.info("Error: " + response.getError().getMessage());
return;
}
ما میخواهیم برچسبهای چیزها، دستهها یا مضامین شناسایی شده در تصویر را دریافت کنیم:
List<String> labels = response.getLabelAnnotationsList().stream()
.map(annotation -> annotation.getDescription())
.collect(Collectors.toList());
logger.info("Annotations found:");
for (String label: labels) {
logger.info("- " + label);
}
ما علاقه مندیم که رنگ غالب تصویر را بدانیم:
String mainColor = "#FFFFFF";
ImageProperties imgProps = response.getImagePropertiesAnnotation();
if (imgProps.hasDominantColors()) {
DominantColorsAnnotation colorsAnn =
imgProps.getDominantColors();
ColorInfo colorInfo = colorsAnn.getColors(0);
mainColor = rgbHex(
colorInfo.getColor().getRed(),
colorInfo.getColor().getGreen(),
colorInfo.getColor().getBlue());
logger.info("Color: " + mainColor);
}
ما همچنین از یک تابع ابزار برای تبدیل مقادیر قرمز / سبز / آبی به یک کد رنگ هگزادسیمال استفاده می کنیم که می توانیم در شیوه نامه های CSS استفاده کنیم.
بیایید بررسی کنیم که آیا تصویر برای نمایش امن است یا خیر:
boolean isSafe = false;
if (response.hasSafeSearchAnnotation()) {
SafeSearchAnnotation safeSearch =
response.getSafeSearchAnnotation();
isSafe = Stream.of(
safeSearch.getAdult(), safeSearch.getMedical(), safeSearch.getRacy(),
safeSearch.getSpoof(), safeSearch.getViolence())
.allMatch( likelihood ->
likelihood != Likelihood.LIKELY && likelihood != Likelihood.VERY_LIKELY
);
logger.info("Safe? " + isSafe);
}
ما در حال بررسی ویژگیهای بزرگسالان / جعل / پزشکی / خشونت / نژادپرستانه هستیم تا ببینیم احتمال آن وجود ندارد یا بسیار محتمل است .
اگر نتیجه جستجوی ایمن درست باشد، میتوانیم متادیتا را در Firestore ذخیره کنیم:
if (isSafe) {
FirestoreOptions firestoreOptions = FirestoreOptions.getDefaultInstance();
Firestore pictureStore = firestoreOptions.getService();
DocumentReference doc = pictureStore.collection("pictures").document(fileName);
Map<String, Object> data = new HashMap<>();
data.put("labels", labels);
data.put("color", mainColor);
data.put("created", new Date());
ApiFuture<WriteResult> writeResult = doc.set(data, SetOptions.merge());
logger.info("Picture metadata saved in Firestore at " + writeResult.get().getUpdateTime());
}
12. تابع را مستقر کنید
زمان استقرار تابع است.
دکمه DEPLOY
را فشار دهید و نسخه جدید مستقر می شود، می توانید پیشرفت را مشاهده کنید:
13. دوباره تابع را تست کنید
پس از اجرای موفقیت آمیز تابع، تصویری را به Cloud Storage ارسال می کنید، ببینید آیا تابع ما فراخوانی شده است، Vision API چه چیزی را برمی گرداند، و آیا ابرداده در Firestore ذخیره می شود.
به Cloud Storage
برگردید و روی سطلی که در ابتدای آزمایشگاه ایجاد کردیم کلیک کنید:
پس از ورود به صفحه جزئیات سطل، روی دکمه Upload files
کلیک کنید تا یک عکس آپلود شود.
از منوی "همبرگر" (☰)، به Logging > Logs
Explorer بروید.
در انتخابگر Log Fields
، Cloud Function
انتخاب کنید تا گزارش های اختصاص داده شده به عملکردهای خود را ببینید. در قسمت Log Fields به پایین اسکرول کنید و حتی می توانید یک تابع خاص را انتخاب کنید تا نمای دقیق تری از گزارش های مربوط به توابع داشته باشید. عملکرد picture-uploaded
انتخاب کنید.
و در واقع، در لیست گزارش ها، می توانم ببینم که تابع ما فراخوانی شده است:
گزارش ها شروع و پایان اجرای تابع را نشان می دهد. و در این بین، ما می توانیم گزارش هایی را که در تابع خود قرار داده ایم با دستورات console.log() ببینیم. می بینیم:
- جزئیات رویدادی که عملکرد ما را تحریک می کند،
- نتایج خام از فراخوانی Vision API،
- برچسب هایی که در تصویری که آپلود کردیم یافت شد،
- اطلاعات رنگ های غالب،
- اینکه آیا تصویر برای نشان دادن بی خطر است،
- و در نهایت آن ابرداده های مربوط به تصویر در Firestore ذخیره شده است.
دوباره از منوی "همبرگر" (☰)، به بخش Firestore
بروید. در زیر بخش Data
(به طور پیش فرض نشان داده شده است)، باید مجموعه pictures
را با یک سند جدید اضافه کنید، مطابق با تصویری که اخیراً آپلود کرده اید:
14. تمیز کردن (اختیاری)
اگر قصد ندارید با دیگر آزمایشگاههای این سری ادامه دهید، میتوانید منابع را پاکسازی کنید تا در هزینهها صرفهجویی کنید و در کل شهروند ابری خوبی باشید. می توانید منابع را به صورت جداگانه به صورت زیر پاک کنید.
سطل را حذف کنید:
gsutil rb gs://${BUCKET_PICTURES}
حذف تابع:
gcloud functions delete picture-uploaded --region europe-west1 -q
با انتخاب حذف مجموعه از مجموعه، مجموعه Firestore را حذف کنید:
یا می توانید کل پروژه را حذف کنید:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
15. تبریک می گویم!
تبریک می گویم! شما اولین سرویس کلیدی پروژه را با موفقیت اجرا کردید!
آنچه را پوشش داده ایم
- فضای ذخیره سازی ابری
- توابع ابری
- Cloud Vision API
- Cloud Firestore