439 lines
17 KiB
TypeScript
439 lines
17 KiB
TypeScript
import config from "../../config/config"
|
|
import FormData from 'form-data'
|
|
import axios from 'axios'
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
async function calculate_phash_features(image_id: number, image: Buffer) {
|
|
const form = new FormData()
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
form.append('image_id', image_id.toString())
|
|
const status = await axios.post(`${config.phash_microservice_url}/calculate_phash_features`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return status.data
|
|
}
|
|
|
|
async function calculate_local_features(image_id: number, image: Buffer) {
|
|
const form = new FormData()
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
form.append('image_id', image_id.toString())
|
|
const status = await axios.post(`${config.local_features_microservice_url}/calculate_local_features`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return status.data
|
|
}
|
|
|
|
async function calculate_global_features(image_id: number, image: Buffer) {
|
|
const form = new FormData()
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
form.append('image_id', image_id.toString())
|
|
const status = await axios.post(`${config.global_features_microservice_url}/calculate_global_features`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return status.data
|
|
}
|
|
|
|
async function calculate_image_text_features(image_id: number, image: Buffer) {
|
|
const form = new FormData()
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
form.append('image_id', image_id.toString())
|
|
const status = await axios.post(`${config.image_text_features_microservice_url}/calculate_image_text_features`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return status.data
|
|
}
|
|
async function calculate_color_features(image_id: number, image: Buffer) {
|
|
const form = new FormData()
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
form.append('image_id', image_id.toString())
|
|
const status = await axios.post(`${config.color_microservice_url}/calculate_color_features`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return status.data
|
|
}
|
|
|
|
// async function calculate_text_features(image_id: number, image: Buffer) {
|
|
// const form = new FormData()
|
|
// form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
// form.append('image_id', image_id.toString())
|
|
// const status = await axios.post(`${config.text_microservice_url}/calculate_text_features`, form.getBuffer(), {
|
|
// maxContentLength: Infinity,
|
|
// maxBodyLength: Infinity,
|
|
// headers: {
|
|
// ...form.getHeaders()
|
|
// }
|
|
// })
|
|
// return status.data
|
|
// }
|
|
|
|
interface ImageSearchProps {
|
|
image: Buffer,
|
|
k?: number,
|
|
distance_threshold?: number
|
|
k_clusters?: number
|
|
knn_min_matches?: number
|
|
matching_threshold?: number
|
|
aqe_n?: number
|
|
aqe_alpha?: number
|
|
use_smnn_matching?: number
|
|
smnn_match_threshold?: number
|
|
use_ransac?: number
|
|
}
|
|
|
|
async function phash_get_similar_images_by_image_buffer({ image, k, distance_threshold }: ImageSearchProps) {
|
|
try {
|
|
const form = new FormData()
|
|
if (k) {
|
|
form.append('k', k.toString())
|
|
} else if (distance_threshold) {
|
|
form.append('distance_threshold', distance_threshold.toString())
|
|
}
|
|
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
const res = await axios.post(`${config.phash_microservice_url}/phash_get_similar_images_by_image_buffer`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return res.data
|
|
} catch (err) {
|
|
console.log(err)
|
|
return []
|
|
}
|
|
}
|
|
|
|
async function global_features_get_similar_images_by_image_buffer({ image, k, distance_threshold, aqe_n, aqe_alpha }: ImageSearchProps) {
|
|
try {
|
|
const form = new FormData()
|
|
if (k) {
|
|
form.append('k', k.toString())
|
|
} else if (distance_threshold) {
|
|
form.append('distance_threshold', distance_threshold.toString())
|
|
}
|
|
if (aqe_n) {
|
|
form.append('aqe_n', aqe_n.toString())
|
|
}
|
|
if (aqe_alpha) {
|
|
form.append('aqe_alpha', aqe_alpha.toString())
|
|
}
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
const res = await axios.post(`${config.global_features_microservice_url}/global_features_get_similar_images_by_image_buffer`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return res.data
|
|
} catch (err) {
|
|
console.log(err)
|
|
return []
|
|
}
|
|
}
|
|
|
|
async function image_text_features_get_similar_images_by_image_buffer({ image, k, distance_threshold, aqe_n, aqe_alpha }: ImageSearchProps) {
|
|
try {
|
|
const form = new FormData()
|
|
if (k) {
|
|
form.append('k', k.toString())
|
|
} else if (distance_threshold) {
|
|
form.append('distance_threshold', distance_threshold.toString())
|
|
}
|
|
if (aqe_n) {
|
|
form.append('aqe_n', aqe_n.toString())
|
|
}
|
|
if (aqe_alpha) {
|
|
form.append('aqe_alpha', aqe_alpha.toString())
|
|
}
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
const res = await axios.post(`${config.image_text_features_microservice_url}/image_text_features_get_similar_images_by_image_buffer`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return res.data
|
|
} catch (err) {
|
|
console.log(err)
|
|
return []
|
|
}
|
|
}
|
|
|
|
async function color_get_similar_images_by_image_buffer({ image, k, distance_threshold }: ImageSearchProps) {
|
|
try {
|
|
const form = new FormData()
|
|
if (k) {
|
|
form.append('k', k.toString())
|
|
} else if (distance_threshold) {
|
|
form.append('distance_threshold', distance_threshold.toString())
|
|
}
|
|
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
const res = await axios.post(`${config.color_microservice_url}/color_get_similar_images_by_image_buffer`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return res.data
|
|
} catch (err) {
|
|
console.log(err)
|
|
return []
|
|
}
|
|
}
|
|
|
|
async function local_features_get_similar_images_by_image_buffer({ image,
|
|
k, k_clusters, knn_min_matches, matching_threshold, use_smnn_matching, smnn_match_threshold, use_ransac }: ImageSearchProps) {
|
|
try {
|
|
const form = new FormData()
|
|
if (k) {
|
|
form.append('k', k.toString())
|
|
}
|
|
if (k_clusters) {
|
|
form.append('k_clusters', k_clusters.toString())
|
|
}
|
|
if (knn_min_matches) {
|
|
form.append('knn_min_matches', knn_min_matches.toString())
|
|
}
|
|
if (matching_threshold) {
|
|
form.append('matching_threshold', matching_threshold.toString())
|
|
}
|
|
if (use_smnn_matching) {
|
|
form.append('use_smnn_matching', use_smnn_matching.toString())
|
|
}
|
|
if (smnn_match_threshold) {
|
|
form.append('smnn_match_threshold', smnn_match_threshold.toString())
|
|
}
|
|
if (use_ransac) {
|
|
form.append('use_ransac', use_ransac.toString())
|
|
}
|
|
|
|
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
const res = await axios.post(`${config.local_features_microservice_url}/local_features_get_similar_images_by_image_buffer`, form.getBuffer(), {
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
headers: {
|
|
...form.getHeaders()
|
|
}
|
|
})
|
|
return res.data
|
|
} catch (err) {
|
|
console.log(err)
|
|
return []
|
|
}
|
|
}
|
|
|
|
// async function text_get_similar_images_by_image_buffer({image,k,distance_threshold}:ImageSearchProps) {
|
|
// try {
|
|
// const form = new FormData()
|
|
// if(k){
|
|
// form.append('k', k.toString())
|
|
// }else if(distance_threshold){
|
|
// form.append('distance_threshold', distance_threshold.toString())
|
|
// }
|
|
|
|
// form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
|
// const res = await axios.post(`${config.text_microservice_url}/text_get_similar_images_by_image_buffer`, form.getBuffer(), {
|
|
// maxContentLength: Infinity,
|
|
// maxBodyLength: Infinity,
|
|
// headers: {
|
|
// ...form.getHeaders()
|
|
// }
|
|
// })
|
|
// return res.data
|
|
// } catch (err) {
|
|
// console.log(err)
|
|
// return []
|
|
// }
|
|
// }
|
|
|
|
async function get_similar_images(image: Buffer,find_duplicate:boolean) {
|
|
let phash_res:any = []
|
|
let global_features_res:any = []
|
|
let local_features_res:any = []
|
|
let color_res:any = []
|
|
let image_text_res:any = [];
|
|
// const text_res = await text_get_similar_images_by_image_buffer({image:image,k:200})
|
|
if(find_duplicate){
|
|
local_features_res = (await local_features_get_similar_images_by_image_buffer({
|
|
image: image, k: 5, k_clusters: 15,
|
|
knn_min_matches: 1, matching_threshold: 0.8,
|
|
use_smnn_matching: 1, use_ransac: 1
|
|
})).filter((el:any)=>el["matches"]>=8)
|
|
}else{
|
|
[phash_res, global_features_res,local_features_res,color_res,image_text_res] = (await Promise.allSettled([
|
|
phash_get_similar_images_by_image_buffer({ image: image, k: 200 }),
|
|
global_features_get_similar_images_by_image_buffer({ image: image, k: 200 }),
|
|
local_features_get_similar_images_by_image_buffer({
|
|
image: image, k: 200, k_clusters: 10,
|
|
knn_min_matches: 1, matching_threshold: 0.8,
|
|
use_smnn_matching: 1, use_ransac: 1
|
|
}),
|
|
color_get_similar_images_by_image_buffer({ image: image, k: 200 }),
|
|
image_text_features_get_similar_images_by_image_buffer({ image: image, k: 200 })
|
|
])).map((promise: any) => promise.value)
|
|
}
|
|
console.log("==================")
|
|
console.log("local_features")
|
|
console.log(local_features_res)
|
|
console.log("==================")
|
|
|
|
console.log("==================")
|
|
console.log("phash")
|
|
console.log(phash_res)
|
|
console.log("==================")
|
|
|
|
console.log("==================")
|
|
console.log("global_features")
|
|
console.log(global_features_res)
|
|
console.log("==================")
|
|
|
|
console.log("==================")
|
|
console.log("color")
|
|
console.log(color_res)
|
|
console.log("==================")
|
|
|
|
// console.log("==================")
|
|
// console.log("text")
|
|
// console.log(text_res)
|
|
// console.log("==================")
|
|
|
|
const _unified_res: { [key: string]: any } = {}
|
|
const unified_res = []
|
|
for (const data_source of [[phash_res, "phash_res"],
|
|
[global_features_res, "global_features_res"], [local_features_res, "local_features_res"],
|
|
[color_res, "color_res"], [image_text_res, "image_text_res"]]) {
|
|
for (let i = 0; i < data_source[0].length; i++) {
|
|
const res = data_source[0][i]
|
|
if (!_unified_res[res.image_id]) {
|
|
_unified_res[res.image_id] = {}
|
|
}
|
|
_unified_res[res.image_id][data_source[1]] = i
|
|
}
|
|
}
|
|
console.log(_unified_res)
|
|
for (const image of Object.entries(_unified_res)) {
|
|
if (Object.entries(image[1]).length > 1) {
|
|
let score = 0
|
|
for (const data_source in image[1]) {
|
|
const idx_in_results = image[1][data_source] + 1
|
|
let multiplier = 1
|
|
switch (data_source) {
|
|
case "global_features_res":
|
|
multiplier = 1
|
|
break
|
|
case "local_features_res":
|
|
multiplier = 1
|
|
break
|
|
case "color_res":
|
|
multiplier = 1
|
|
break
|
|
case "image_text_res":
|
|
multiplier = 1
|
|
break
|
|
case "phash_res":
|
|
multiplier = 1
|
|
break
|
|
}
|
|
score += multiplier * (1 / idx_in_results)
|
|
}
|
|
unified_res.push({ image_id: parseInt(image[0]), score: score })
|
|
}
|
|
}
|
|
const all_results: any = {}
|
|
for (const data_source of [[phash_res, "phash_res"],
|
|
[global_features_res, "global_features_res"], [local_features_res, "local_features_res"],
|
|
[color_res, "color_res"], [image_text_res, "image_text_res"]]) {
|
|
if (data_source[0].length!==0){
|
|
all_results[data_source[1]] = data_source[0].slice(0,20)
|
|
}
|
|
}
|
|
if (unified_res.length !== 0) {
|
|
all_results.unified_res = unified_res.sort((a:any,b:any)=>-(a.score-b.score))
|
|
}
|
|
return all_results
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
async function delete_local_features_by_id(image_id: number) {
|
|
const status = await axios.post(`${config.local_features_microservice_url}/delete_local_features`, { image_id: image_id })
|
|
return status.data
|
|
}
|
|
|
|
async function delete_global_features_by_id(image_id: number) {
|
|
const status = await axios.post(`${config.global_features_microservice_url}/delete_global_features`, { image_id: image_id })
|
|
return status.data
|
|
}
|
|
|
|
async function delete_image_text_features_by_id(image_id: number) {
|
|
const status = await axios.post(`${config.image_text_features_microservice_url}/delete_image_text_features`, { image_id: image_id })
|
|
return status.data
|
|
}
|
|
|
|
async function delete_color_features_by_id(image_id: number) {
|
|
const status = await axios.post(`${config.color_microservice_url}/delete_color_features`, { image_id: image_id })
|
|
return status.data
|
|
}
|
|
|
|
async function delete_phash_features_by_id(image_id: number) {
|
|
const status = await axios.post(`${config.phash_microservice_url}/delete_phash_features`, { image_id: image_id })
|
|
return status.data
|
|
}
|
|
|
|
// async function delete_text_features_by_id(image_id: number) {
|
|
// const status = await axios.post(`${config.text_microservice_url}/delete_text_features`, { image_id: image_id })
|
|
// return status.data
|
|
// }
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
async function calculate_all_image_features(image_id: number, image_buffer: Buffer) {
|
|
return Promise.allSettled([
|
|
calculate_global_features(image_id, image_buffer),
|
|
calculate_local_features(image_id, image_buffer),
|
|
calculate_color_features(image_id, image_buffer),
|
|
calculate_phash_features(image_id, image_buffer),
|
|
calculate_image_text_features(image_id, image_buffer),
|
|
// calculate_text_features(image_id, image_buffer)
|
|
])
|
|
}
|
|
|
|
async function delete_all_image_features(image_id: number) {
|
|
return Promise.allSettled([
|
|
delete_global_features_by_id(image_id),
|
|
delete_local_features_by_id(image_id),
|
|
delete_color_features_by_id(image_id),
|
|
delete_phash_features_by_id(image_id),
|
|
delete_image_text_features_by_id(image_id)
|
|
// delete_text_features_by_id(image_id)
|
|
])
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
export default { calculate_all_image_features, delete_all_image_features, get_similar_images } |