add new microservice

main
qwertyforce 2022-08-29 22:45:23 +03:00
parent 1506ff8ed5
commit a710115c10
4 changed files with 263 additions and 111 deletions

View File

@ -4,5 +4,8 @@ export default {
global_features_microservice_url:"http://127.0.0.1:33334",
color_microservice_url:"http://127.0.0.1:33335",
phash_microservice_url:"http://127.0.0.1:33336",
image_text_features_microservice_url: "http://127.0.0.1:33338",
text_microservice_url:"http://127.0.0.1:33339",
image_caption_microservice_url: "http://127.0.0.1:33340",
image_tags_microservice_url: "http://127.0.0.1:33341",
}

View File

@ -30,6 +30,7 @@ async function calculate_local_features(image_id: number, image: Buffer) {
})
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
@ -44,6 +45,19 @@ async function calculate_global_features(image_id: number, image: Buffer) {
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
@ -58,43 +72,43 @@ async function calculate_color_features(image_id: number, image: Buffer) {
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
// 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
}
interface ImageSearchProps{
image:Buffer,
k?:number,
distance_threshold?:number
k_clusters?:number
min_matches?:number
matching_threshold?:number
aqe_n?:number
aqe_alpha?:number
use_snn_matching?:number
snn_match_threshold?:number
use_ransac?:number
}
async function phash_get_similar_images_by_image_buffer({image,k,distance_threshold}:ImageSearchProps) {
async function phash_get_similar_images_by_image_buffer({ image, k, distance_threshold }: ImageSearchProps) {
try {
const form = new FormData()
if(k){
if (k) {
form.append('k', k.toString())
}else if(distance_threshold){
} 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,
@ -110,18 +124,18 @@ async function phash_get_similar_images_by_image_buffer({image,k,distance_thresh
}
}
async function global_features_get_similar_images_by_image_buffer({image,k,distance_threshold,aqe_n,aqe_alpha}:ImageSearchProps) {
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){
if (k) {
form.append('k', k.toString())
}else if(distance_threshold){
} else if (distance_threshold) {
form.append('distance_threshold', distance_threshold.toString())
}
if(aqe_n){
if (aqe_n) {
form.append('aqe_n', aqe_n.toString())
}
if(aqe_alpha){
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
@ -139,15 +153,44 @@ async function global_features_get_similar_images_by_image_buffer({image,k,dista
}
}
async function color_get_similar_images_by_image_buffer({image,k,distance_threshold}:ImageSearchProps) {
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){
if (k) {
form.append('k', k.toString())
}else if(distance_threshold){
} 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,
@ -163,32 +206,32 @@ async function color_get_similar_images_by_image_buffer({image,k,distance_thresh
}
}
async function local_features_get_similar_images_by_image_buffer({image,
k,k_clusters,min_matches,matching_threshold,use_snn_matching,snn_match_threshold,use_ransac}:ImageSearchProps) {
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){
if (k) {
form.append('k', k.toString())
}
if(k_clusters){
if (k_clusters) {
form.append('k_clusters', k_clusters.toString())
}
if(min_matches){
form.append('min_matches', min_matches.toString())
if (knn_min_matches) {
form.append('knn_min_matches', knn_min_matches.toString())
}
if(matching_threshold){
if (matching_threshold) {
form.append('matching_threshold', matching_threshold.toString())
}
if(use_snn_matching){
form.append('use_snn_matching', use_snn_matching.toString())
if (use_smnn_matching) {
form.append('use_smnn_matching', use_smnn_matching.toString())
}
if(snn_match_threshold){
form.append('snn_match_threshold', snn_match_threshold.toString())
if (smnn_match_threshold) {
form.append('smnn_match_threshold', smnn_match_threshold.toString())
}
if(use_ransac){
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,
@ -204,42 +247,58 @@ async function local_features_get_similar_images_by_image_buffer({image,
}
}
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 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)
}
}
async function get_similar_images(image: Buffer) {
const phash_res = await phash_get_similar_images_by_image_buffer({image:image,k:200})
const global_features_res = await global_features_get_similar_images_by_image_buffer({image:image,k:200})
const local_features_res = await local_features_get_similar_images_by_image_buffer({
image:image,k:200, k_clusters:10,
min_matches:4, matching_threshold:1.1,
use_snn_matching:1, use_ransac:1})
const color_res = await color_get_similar_images_by_image_buffer({image:image,k:200})
const text_res = await text_get_similar_images_by_image_buffer({image:image,k:200})
console.log("==================")
console.log("phash")
console.log("local_features")
console.log(local_features_res)
console.log("==================")
@ -249,7 +308,7 @@ async function get_similar_images(image: Buffer) {
console.log("==================")
console.log("==================")
console.log("nn")
console.log("global_features")
console.log(global_features_res)
console.log("==================")
@ -258,12 +317,66 @@ async function get_similar_images(image: Buffer) {
console.log(color_res)
console.log("==================")
console.log("==================")
console.log("text")
console.log(text_res)
console.log("==================")
return {phash:phash_res,global_features:global_features_res,local_features:local_features_res,color:color_res,text:text_res}
}
// 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
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -278,6 +391,11 @@ async function delete_global_features_by_id(image_id: number) {
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
@ -288,10 +406,10 @@ async function delete_phash_features_by_id(image_id: number) {
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 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
// }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -302,7 +420,8 @@ async function calculate_all_image_features(image_id: number, image_buffer: Buff
calculate_local_features(image_id, image_buffer),
calculate_color_features(image_id, image_buffer),
calculate_phash_features(image_id, image_buffer),
calculate_text_features(image_id, image_buffer)
calculate_image_text_features(image_id, image_buffer),
// calculate_text_features(image_id, image_buffer)
])
}
@ -312,8 +431,9 @@ async function delete_all_image_features(image_id: number) {
delete_local_features_by_id(image_id),
delete_color_features_by_id(image_id),
delete_phash_features_by_id(image_id),
delete_text_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}
export default { calculate_all_image_features, delete_all_image_features, get_similar_images }

View File

@ -91,6 +91,16 @@ global_features_routes.forEach((r) => server.post(r, (_req, res) => {
}
}))
const image_text_features_routes = ['/image_text_features_get_similar_images_by_image_buffer', '/image_text_features_get_similar_images_by_id', '/image_text_features_get_similar_images_by_text', '/calculate_image_text_features', '/delete_image_text_features']
image_text_features_routes.forEach((r) => server.post(r, (_req, res) => {
try {
res.from(combineURLs(config.image_text_features_microservice_url, r))
} catch (err) {
console.log(err)
res.status(500).send('image_text features microservice is down')
}
}))
const color_routes = ['/color_get_similar_images_by_image_buffer', '/color_get_similar_images_by_id', '/calculate_color_features', '/delete_color_features']
color_routes.forEach((r) => server.post(r, (_req, res) => {
try {
@ -101,15 +111,15 @@ color_routes.forEach((r) => server.post(r, (_req, res) => {
}
}))
const text_routes = ['/text_get_similar_images_by_image_buffer', '/text_get_similar_images_by_id', '/calculate_text_features', '/delete_text_features']
text_routes.forEach((r) => server.post(r, (_req, res) => {
try {
res.from(combineURLs(config.text_microservice_url, r))
} catch (err) {
console.log(err)
res.status(500).send('Text features microservice is down')
}
}))
// const text_routes = ['/text_get_similar_images_by_image_buffer', '/text_get_similar_images_by_id', '/calculate_text_features', '/delete_text_features']
// text_routes.forEach((r) => server.post(r, (_req, res) => {
// try {
// res.from(combineURLs(config.text_microservice_url, r))
// } catch (err) {
// console.log(err)
// res.status(500).send('Text features microservice is down')
// }
// }))
const phash_routes = ['/phash_get_similar_images_by_image_buffer', '/calculate_phash_features', '/delete_phash_features']
phash_routes.forEach((r) => server.post(r, (_req, res) => {
@ -120,6 +130,24 @@ phash_routes.forEach((r) => server.post(r, (_req, res) => {
res.status(500).send('Phash microservice is down')
}
}))
server.post("/get_image_tags", (_req, res) => {
try {
res.from(combineURLs(config.image_tags_microservice_url, "/get_image_tags"))
} catch (err) {
console.log(err)
res.status(500).send('image tagging microservice is down')
}
})
server.post("/get_image_caption", (_req, res) => {
try {
res.from(combineURLs(config.image_caption_microservice_url, "/get_image_caption"))
} catch (err) {
console.log(err)
res.status(500).send('image caption microservice is down')
}
})
////////////////////////////////////////////////////////////////////////////////////////////////////////////
server.listen({port:port, host:"127.0.0.1"}, function (err, address) {

View File

@ -12,7 +12,8 @@ const body_schema_reverse_search = {
limit: { type: 'boolean' },
mimetype: { type: 'string' }
}
}
},
find_duplicate: {type: 'string'}
},
required: ['image'],
} as const;
@ -24,7 +25,7 @@ async function reverse_search(req: FastifyRequest<{ Body: FromSchema<typeof body
} catch (err) {
return res.status(500).send()
}
const results = await image_ops.get_similar_images(image_buffer)
const results = await image_ops.get_similar_images(image_buffer,Boolean(parseInt(req.body?.find_duplicate||"0")))
return results
}