Working aobrtable perspective search

master
Kuba Orlik 4 years ago
parent 8c4fd2d4cc
commit 04a4fa2953

20
package-lock.json generated

@ -9,7 +9,9 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"abortable-promise": "git+https://git.kuba-orlik.name/kuba/abortable-promises.git#ee3d998",
"async-spawner": "git+https://git.kuba-orlik.name/kuba/async-spawner.git#7ee6a21", "async-spawner": "git+https://git.kuba-orlik.name/kuba/async-spawner.git#7ee6a21",
"emittery": "^0.8.1",
"tempy": "^1.0.1" "tempy": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
@ -53,6 +55,16 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz",
"integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==" "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag=="
}, },
"node_modules/abortable-promise": {
"version": "0.1.0",
"resolved": "git+https://git.kuba-orlik.name/kuba/abortable-promises.git#ee3d998c08b43a2efb15d921f592e8fdc433f487",
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
"@types/node": "^14.14.19",
"emittery": "^0.8.1"
}
},
"node_modules/aggregate-error": { "node_modules/aggregate-error": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
@ -606,6 +618,14 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz",
"integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==" "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag=="
}, },
"abortable-promise": {
"version": "git+https://git.kuba-orlik.name/kuba/abortable-promises.git#ee3d998c08b43a2efb15d921f592e8fdc433f487",
"from": "abortable-promise@git+https://git.kuba-orlik.name/kuba/abortable-promises.git#ee3d998",
"requires": {
"@types/node": "^14.14.19",
"emittery": "^0.8.1"
}
},
"aggregate-error": { "aggregate-error": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",

@ -10,7 +10,9 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"async-spawner": "git+https://git.kuba-orlik.name/kuba/async-spawner.git#7ee6a21", "abortable-promise": "git+https://git.kuba-orlik.name/kuba/abortable-promises.git#4a316bb",
"async-spawner": "git+https://git.kuba-orlik.name/kuba/async-spawner.git#cdbb47d",
"emittery": "^0.8.1",
"tempy": "^1.0.1" "tempy": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {

@ -0,0 +1,96 @@
import { deferedSpawn } from "async-spawner";
import Emittery from "emittery";
import { promisify } from "util";
//needed to pass information on wether or not the promise has been aborted witout 'this'
class AbortableEmittery extends Emittery {
public aborted = false;
abort() {
this.aborted = true;
this.emit("abort");
}
}
class AbortablePromise<T> extends Promise<T | null> {
private emitter: AbortableEmittery;
constructor(
make_generator: (
await_or_abort: (
promise: Promise<any>,
on_abort: () => void
) => Promise<void>
) => AsyncGenerator
) {
const emitter = new AbortableEmittery();
const await_or_abort = (
promise: Promise<any>,
on_abort: () => void
) => {
return new Promise((resolve, reject) => {
let resolved = false;
emitter.on("abort", () => {
if (!resolved) {
on_abort();
resolve(null);
resolved = true;
}
});
promise
.then((result) => {
if (!resolved) {
resolve(result);
resolved = true;
}
})
.catch(reject);
});
};
super(async (resolve, reject) => {
let step_value;
const generator = make_generator(await_or_abort);
do {
if (emitter.aborted) {
resolve(null);
return;
}
step_value = await generator.next();
} while (!step_value.done);
});
this.emitter = emitter;
}
abort() {
this.emitter.abort();
}
}
// const sleep = promisify((timeout: number, callback: (...args: any[]) => void) =>
// setTimeout(callback, timeout)
// );
// const a = new AbortablePromise(async function* () {
// yield await sleep(1000);
// console.log("awaited 100");
// yield await sleep(2000);
// console.log("awaited 200");
// yield await sleep(3000);
// console.log("awaited 300");
// });
// setTimeout(() => a.abort(), 1500);
const b = new AbortablePromise(async function* (await_or_abort) {
const ping = await deferedSpawn("ping", ["8.8.8.8"]);
while (true) {
console.log(
await await_or_abort(ping.waitForNextData(), () => {
ping.kill();
})
);
yield;
}
});
setTimeout(() => b.abort(), 5000);

@ -1,10 +1,18 @@
import simpleSpawn from "async-spawner"; import AbortablePromise from "abortable-promise";
import { deferedSpawn } from "async-spawner";
import tempy from "tempy"; import tempy from "tempy";
import {
newpos,
transformCoefs,
transformDesc,
transforms,
} from "./transforms";
async function perspectiveShift( function perspectiveShift(
input: string, input: string,
shift: transformCoefs shift: transformCoefs
): Promise<string> { ): AbortablePromise<string> {
return new AbortablePromise(async function* (await_or_abort) {
const output = tempy.file({ extension: "jpg" }); const output = tempy.file({ extension: "jpg" });
const args = [ const args = [
"-verbose", "-verbose",
@ -16,9 +24,12 @@ async function perspectiveShift(
shift.join(","), shift.join(","),
output, output,
]; ];
console.log(args); const def = await deferedSpawn("convert", args);
await simpleSpawn("convert", args); const next_data_promise = def.waitForNextData();
return output; // the file name; yield;
await await_or_abort(next_data_promise, () => def.kill());
return output;
});
} }
type coordinates = { x: number; y: number }; type coordinates = { x: number; y: number };
@ -28,7 +39,7 @@ type alpr_candidate = {
matches_template: 0 | 1; matches_template: 0 | 1;
}; };
type alpr_response = { export type alpr_response = {
version: number; version: number;
data_type: "alpr_results"; data_type: "alpr_results";
epoch_time: number; epoch_time: number;
@ -68,8 +79,12 @@ function empty_alpr_response() {
}; };
} }
export default async function alpr(path: string): Promise<alpr_response> { type DeferedSpawn = ReturnType<typeof deferedSpawn>;
const result = await simpleSpawn("alpr", [
export function alpr(path: string): AbortablePromise<alpr_response> {
return new AbortablePromise(async function* (await_or_abort) {
console.log("Running alpr abortablepromise");
const def = await deferedSpawn("alpr", [
"-c", "-c",
"eu", "eu",
"-p", "-p",
@ -77,26 +92,33 @@ export default async function alpr(path: string): Promise<alpr_response> {
"-j", "-j",
path, path,
]); ]);
return JSON.parse(result.stdout); console.log("created deferedspawn");
} const answer_promise = def.waitForNextData();
yield;
function newpos( const answer = await await_or_abort(answer_promise, () => def.kill());
x: number, console.log("got answer!");
y: number, return JSON.parse((answer as unknown) as string);
t: transformCoefs });
): { x: number; y: number } {
return {
x: (x * t[0] + y * t[1] + t[2]) / (t[6] * x + t[7] * y + 1),
y: (x * t[3] + y * t[4] + t[5]) / (t[6] * x + t[7] * y + 1),
};
} }
export async function perspectiveAssistedAlpr( export function perspectiveAssistedAlpr(
input: string, input: string,
shift: transformDesc shift: transformDesc
) { ): AbortablePromise<alpr_response> {
const shifted_image = await perspectiveShift(input, shift.forward); console.log("new ap perspectiveAlpr");
let result = await alpr(shifted_image); return new AbortablePromise(async function* (await_or_abort) {
const shifted_image = await await_or_abort(
perspectiveShift(input, shift.forward)
);
yield;
console.log("after yield1");
let result = await await_or_abort(alpr(shifted_image));
yield;
console.log("after yield2");
console.log("~~~Got perspective shifted response");
if (result === null) {
return null;
}
for (const i in result.results) { for (const i in result.results) {
result.results[i].coordinates = result.results[i].coordinates.map( result.results[i].coordinates = result.results[i].coordinates.map(
(c) => { (c) => {
@ -108,73 +130,65 @@ export async function perspectiveAssistedAlpr(
) as [coordinates, coordinates, coordinates, coordinates]; ) as [coordinates, coordinates, coordinates, coordinates];
} }
return result; return result;
});
} }
type transformCoefs = [ // export function alprMultiPersp(input: string): AbortablePromise<alpr_response> {
number, // return new AbortablePromise(async function* (await_or_abort) {
number, // let resolved = false;
number, // return new Promise((resolve, reject): void => {
number, // let promises: Array<AbortablePromise<any> | Promise<any>> = [];
number, // const callback = (arg: alpr_response) => {
number, // if (resolved) {
number, // return;
number // }
]; // if (arg.results.length === 0) {
type transformDesc = { forward: transformCoefs; backward: transformCoefs }; // return;
// }
// See perspective.md to learn how coefficients are created for calls below: // resolved = true;
const transforms: transformDesc[] = [ // for (const promise of promises) {
{ // if (promise instanceof AbortablePromise) {
forward: [ // console.log("aovrting promise!");
0.418385, // promise.abort();
-0.064912, // }
1.11204e-12, // }
-1.07285e-16, // resolve(arg);
0.407118, // };
1.85136e-13, // promises = [
-0.000143964, // alpr(input).then(callback),
-0.0000155811, // ...transforms.map((transform) =>
], // perspectiveAssistedAlpr(input, transform).then(callback)
backward: [ // ),
2.39014, // ];
0.381091, // Promise.all(promises)
-5.07071e-13, // .then(() => {
8.09745e-16, // if (!resolved) {
2.45629, // resolve(empty_alpr_response());
-1.95474e-12, // }
0.000344095, // })
0.0000931351, // .catch(reject);
// });
// });
// }
//
export function alprMultiPersp(input: string): AbortablePromise<alpr_response> {
const ret = AbortablePromise.deadlyRace<alpr_response>(
[
alpr(input),
// ...transforms.map((transform) =>
// perspectiveAssistedAlpr(input, transform)
// ),
perspectiveAssistedAlpr(input, transforms[0]),
], ],
}, async (arg: alpr_response) => {
]; return arg.results.length > 0;
export async function alprMultiPersp(input: string): Promise<alpr_response> {
let resolved = false;
return new Promise((resolve, reject) => {
const callback = (arg: alpr_response) => {
if (resolved) {
return;
}
if (arg.results.length === 0) {
return;
} }
resolved = true; );
resolve(arg); return ret;
}; // return new Promise((resolve, reject) => {
Promise.all([ // alpr(input).then(resolve, reject);
alpr(input).then(callback), // });
...transforms.map((transform) => // return new Promise((resolve, reject) => {
perspectiveAssistedAlpr(input, transform).then(callback) // perspectiveAssistedAlpr(input, transforms[0]);
), // });
])
.then(() => {
if (!resolved) {
resolve(empty_alpr_response());
}
})
.catch(reject);
});
} }
console.log(newpos(4040, 0, transforms[0].forward));
console.log(newpos(4040, 0, transforms[0].backward));

@ -1,22 +1,30 @@
import simpleSpawn, { deferedSpawn } from "async-spawner"; import simpleSpawn, { deferedSpawn } from "async-spawner";
import { promises as fs } from "fs"; import { promises as fs } from "fs";
import path from "path"; import path from "path";
import { alprMultiPersp } from "./alpr"; import AbortablePromise from "../../abortable-promise/@types";
import { alprMultiPersp, alpr_response } from "./alpr";
async function run(): Promise<void> { async function run(): Promise<void> {
const gui = await deferedSpawn("python", [ const gui = await deferedSpawn("python", [
"/home/kuba/projects/personal/qml-player/main.py", "/home/kuba/projects/personal/qml-player/main.py",
"/home/kuba/projects/personal/qml-player/template.qml", "/home/kuba/projects/personal/qml-player/template.qml",
]); ]);
const dir = const dir = "/home/kuba/projects/personal/zgłaszańska/03-20_2/";
"/home/kuba/projects/personal/zgłaszańska/03-20_2/problematic_cars";
const files = await fs.readdir(dir); const files = await fs.readdir(dir);
let multi_perp_promise: AbortablePromise<alpr_response> | null = null;
for (const file of files.filter((f) => f.includes("jpg"))) { for (const file of files.filter((f) => f.includes("jpg"))) {
const full_path = path.resolve(dir, file); const full_path = path.resolve(dir, file);
void alprMultiPersp(full_path).then((o) => { if (multi_perp_promise) {
multi_perp_promise.abort();
}
multi_perp_promise = alprMultiPersp(full_path);
multi_perp_promise
.then((o) => {
if (o === null) return;
console.log("Got coords!"); console.log("Got coords!");
const { img_width, img_height } = o; const { img_width, img_height } = o;
if (o.results.length) { if (o.results.length) {
console.log(o.results[0]);
const min_x = Math.min( const min_x = Math.min(
...o.results[0].coordinates.map((c: any) => c.x) ...o.results[0].coordinates.map((c: any) => c.x)
); );
@ -49,7 +57,8 @@ async function run(): Promise<void> {
} else { } else {
gui.write(JSON.stringify({ rect_width: 0 })); gui.write(JSON.stringify({ rect_width: 0 }));
} }
}); })
.catch(console.error);
gui.write( gui.write(
JSON.stringify({ JSON.stringify({
current_image: full_path, current_image: full_path,
@ -64,4 +73,4 @@ async function run(): Promise<void> {
} }
} }
run(); run().catch(console.error);

@ -0,0 +1,139 @@
export function newpos(
x: number,
y: number,
t: transformCoefs
): { x: number; y: number } {
return {
x: (x * t[0] + y * t[1] + t[2]) / (t[6] * x + t[7] * y + 1),
y: (x * t[3] + y * t[4] + t[5]) / (t[6] * x + t[7] * y + 1),
};
}
export type transformCoefs = [
number,
number,
number,
number,
number,
number,
number,
number
];
export type transformDesc = {
forward: transformCoefs;
backward: transformCoefs;
};
// See perspective.md to learn how coefficients are created for calls below:
export const transforms: transformDesc[] = [
{
forward: [
0.418385,
-0.064912,
1.11204e-12,
-1.07285e-16,
0.407118,
1.85136e-13,
-0.000143964,
-0.0000155811,
],
backward: [
2.39014,
0.381091,
-5.07071e-13,
8.09745e-16,
2.45629,
-1.95474e-12,
0.000344095,
0.0000931351,
],
},
{
forward: [
1.52043,
3.31591e-16,
-9.50693e-13,
4.91024e-16,
1.29283,
-4.86523e-28,
0.00012882,
0.000072315,
],
backward: [
0.657707,
2.87435e-16,
-6.72954e-13,
7.80686e-16,
0.773495,
-1.67079e-12,
-0.0000847259,
-0.0000559353,
],
},
{
forward: [
0.894876,
-0.285098,
8.16135e-13,
-4.48986e-17,
1.06368,
1.8139e-13,
-0.0000260208,
-0.0000110713,
],
backward: [
1.11747,
0.299515,
-4.53809e-13,
4.55732e-16,
0.940129,
-4.27521e-13,
0.0000290775,
0.0000182021,
],
},
{
forward: [
1.96875,
8.8124e-16,
-1.34293e-12,
0.725124,
1,
-8.35683e-13,
0.00023979,
7.05268e-19,
],
backward: [
0.507937,
-2.73557e-16,
4.90838e-13,
-0.368317,
1,
-1.03804e-12,
-0.000121798,
-1.49027e-19,
],
},
{
forward: [
3.88517,
0.106038,
-3.10281e-12,
1.43097,
0.722206,
-5.02081e-13,
0.00071415,
-0.0000918632,
],
backward: [
0.272104,
-0.0399518,
-6.63745e-13,
-0.539145,
1.46381,
-8.91691e-12,
-0.000243851,
0.000163002,
],
},
];
Loading…
Cancel
Save