When shopping online, not only can you search for products by name, but you can also take a picture and upload it to search for products. For example, if you take a picture of a certain treasure, you can search for the corresponding goods.
Tencent and Ali both offer similar image search services, which are similar in principle:
- On a specific gallery, add or delete images.
- Search for similar images by image.
This article buttresses theTencent Cloud's Image Search。
Add Configuration
Add a maven dependency:
<dependency>
<groupId></groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.1129</version>
</dependency>
Introducing Configuration:
tencentcloud:
tiia:
secretId: ${SECRET_ID}
secretKey: ${SECRET_KEY}
endpoint:
region: ap-guangzhou
groupId: test1
The secretId and secretKey are both in theAPI Secret Key Address:/cam/capi
The groupId is the gallery id.
Configuring the bean
@Data
@Configuration
@ConfigurationProperties("")
public class TencentCloudTiiaProperties {
private String secretId;
private String secretKey;
private String endpoint = "";
private String region = "ap-guangzhou";
private String groupId;
}
@Configuration
@ConditionalOnClass()
public class TencentCloudTiiaConfig {
@Bean
public TiiaClient tiiaClient(TencentCloudTiiaProperties properties) {
Credential cred = new Credential((), ());
HttpProfile httpProfile = new HttpProfile();
(());
ClientProfile clientProfile = new ClientProfile();
(httpProfile);
TiiaClient client = new TiiaClient(cred, (), clientProfile);
return client;
}
}
tiiaClient is the core of image search, and will be used later to add, delete, and search images.
Gallery Updates
After creating a new gallery, you need to batch import images into the gallery. Usually start to batch import the images from the shelves to the gallery in bulk, usually only need to operate once.
When a product is modified, added or removed from the shelves, the pictures need to be updated accordingly. But every time you update the update operation is synchronized, which may lead to frequent database updates and increased server pressure, you need to change to, every time you update the picture, synchronize it to the cache, and then process the cached data at regular intervals:
Tencent Image Search does not have an image update interface, only an interface for image deletion and addition, thenCall deletion first, then call the added interface
Delete Image
Image Delete Call method, the main attention is paid to the request frequency limit.
Default interface request frequency limit: 10 requests/second
Here's how to handle it simply, using thread delays(100)
To delete an image, simply specify the EntityId:
@Data
public class DeleteImageDTO {
private String entityId;
private List<String> picName;
}
If PicName is specified the specific image under the EntityId is deleted, if PicName is not specified the entire EntityId is deleted.
The code to delete the image is as follows:
public void deleteImage(List<DeleteImageDTO> list) {
if ((list)) {
return;
}
().forEach(deleteImageDTO -> {
List<String> picNameList = ();
if ((picNameList)) {
DeleteImagesRequest request = new DeleteImagesRequest();
(());
(());
try {
// Tencent Restrictionsqps
(100);
(request);
} catch (TencentCloudSDKException | InterruptedException e) {
("Failed to delete image, entityId {} error message {}", (), ());
}
} else {
().forEach(picName -> {
DeleteImagesRequest request = new DeleteImagesRequest();
(());
(());
(picName);
try {
(100);
(request);
} catch (TencentCloudSDKException | InterruptedException e) {
("Failed to delete image, entityId {}, error message {}", (), picName, ());
}
});
}
});
}
New Images
New image call method, here too you need to be aware of the limitations on the frequency of calls. In addition to this there are two other restrictions:
- Limit the size of the image to no more than 5M
- Limit image resolution to no more than resolution 4096*4096
Since compressing images takes time, it's a good idea to compress them first every time you upload them, so that you can solve the problem of limiting the frequency of calls. Compressing images introduces thumbnailator:
<dependency>
<groupId></groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.20</version>
</dependency>
Compression Tool Class:
/**
* Image Compression
* @param url photographurl
* @param scale Compression ratio
* @param targetSizeByte Compressed size KB
* @return
*/
public static byte[] compress(String url, double scale, long targetSizeByte) {
if ((url)) {
return null;
}
long targetSizeKB = targetSizeByte * 1024;
try {
URL u = new URL(url);
double quality = 0.8;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
do {
(u).scale(scale) // Compression ratio
.outputQuality(quality) // photograph质量
.toOutputStream(outputStream);
long fileSize = ();
if (fileSize <= targetSizeKB) {
return ();
}
();
if (quality > 0.1) {
quality -= 0.1;
} else {
scale -= 0.1;
}
} while (quality > 0 || scale > 0);
} catch (IOException e) {
(());
}
return null;
}
Compress the image to a fixed size by reducing the size and reducing the quality of the image, all of which are compressed first here. Solve the problem of call frequency limitation.
Limiting the resolution of an image also uses the size method inside the thumbnailator.
thumbnailator compresses and limits the size of the image, can't be used together, can only be called separately.
Set the size method:
/**
* Image Compression
* @param imageData
* @param width height
* @param height high degree
* @return
*/
public static byte[] compressSize(byte[] imageData,String outputFormat,int width,int height) {
if (imageData == null) {
return null;
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(imageData);
try {
BufferedImage bufferedImage = (inputStream);
int imageWidth = ();
int imageHeight = ();
if (imageWidth <= width && imageHeight <= height) {
return imageData;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
(bufferedImage)
.size(width,height)
.outputFormat(outputFormat)
.toOutputStream(outputStream);
return ();
} catch (IOException e) {
(());
}
return null;
}
Here the width and height are not set directly to the length and length of the image, but they will not be exceeded. If one exceeds the size limit, the size is compressed and the aspect ratio remains the same.
To add an image, specify the EntityId, url, and picName.
@Data
public class AddImageDTO {
private String entityId;
private String imgUrl;
private String picName;
}
With the image compression problem solved, uploading images is easier:
public void uploadImage(List<AddImageDTO> list) {
if ((list)) {
return;
}
().forEach(imageDTO -> {
String imgUrlStr = ();
if ((imgUrlStr)) {
// Skip current element
return;
}
CreateImageRequest request = new CreateImageRequest();
(());
(());
String imageUrl = ();
// limit on size
byte[] bytes = (imageUrl,0.6,1024 * 5);
String imageFormat = ((".") + 1);
// Limiting resolution
bytes = (bytes,imageFormat,4096,4096);
request.setImageBase64(new String(Base64.encodeBase64(bytes), StandardCharsets.UTF_8));
//JSONObject tagJson = new JSONObject();
//("code","Search Fields");
//((tagJson));
(());
try {
(request);
} catch (TencentCloudSDKException e) {
("Image upload failed error:{}", ());
}
});
}
Tags Image custom tags, set the parameters of the image, when searching you can search for different images based on the parameters.
Updated Pictures
General merchandise updates to deposit data into the cache:
String value = "demo key";
SetOperations<String, Object> opsForSet = ();
(RedisKeyConstant.PRODUCT_IMAGE_SYNC_CACHE_KEY, value);
Timing the task again:
public void syncImage() {
while (true) {
SetOperations<String, Object> operations = ();
Object obj = (RedisKeyConstant.PRODUCT_IMAGE_SYNC_CACHE_KEY);
if (obj == null) {
("No mission data found at this time");
return;
}
String pop = ();
if ((pop)) {
continue;
}
DeleteImageDTO deleteImageDTO = new DeleteImageDTO();
(pop);
try {
((deleteImageDTO));
} catch (Exception e) {
("Failed to delete image,entityId {}",pop);
}
// todo Get data specific data
String imageUrl="";
// todo picName Needs to be globally unique
String picName="";
AddImageDTO addImageDTO = new AddImageDTO();
(pop);
(imageUrl);
(picName);
try {
((addImageDTO));
} catch (Exception e) {
("Failed to upload image,entityId {}",pop);
}
}
}
Take a random data from the collection and remove the data, first delete the image and then query the database to see if the data exists, and if it does, add the new image.
Search Images
Image search call method, you need to pass the image byte stream, and compressed images need a file extension.
@Data
public class SearchRequest {
private byte[] bytes;
private String suffix;
}
public ImageInfo [] analysis(SearchRequest searchRequest) throws IOException, TencentCloudSDKException {
SearchImageRequest request = new SearchImageRequest();
(());
// screening,Corresponding upload interface Tags
//("channelCode=\"" + () + "\"");、
byte[] bytes = ();
bytes = (bytes,(),4096,4096);
String base64 = Base64.encodeBase64String(bytes);
request.setImageBase64(base64);
SearchImageResponse searchImageResponse = (request);
return ();
}
Get the EntityId from the returned ImageInfos array, and you can get the corresponding product information.
summarize
Docking the image search, mainly to do the image update and synchronization operations. As opposed to synchronizing the interface every time it is updated, this approach is also more stressful for the server, theSynchronize the data to the cache first, and then process the data at regular intervals., while searching for images for data consistency is relatively lax, decentralizing the pressure of library writes.
Add image use thumbnailator to compress and shrink the image, for the call request frequency limit, add image will compress the image once every time, each time the compression time is probably more than 100ms, to solve the problem of request frequency limit. For deleting an image, it simply uses thread hibernation to hibernate the image for 100ms.
After doing the image update operation, search the gallery using the method will be able to get the corresponding result information.
Github Example
/jeremylai7/springboot-learning/blob/master/springboot-test/src/main/java/com/test/controller/