mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-11 19:00:00 +01:00
Opencv.js via npm for blob-detection (#1185)
This commit is contained in:
@@ -9,6 +9,7 @@ List of Module Documentations
|
||||
4. [Add QR](#Add-QR-module)
|
||||
5. [Average](#average-module)
|
||||
6. [Blend](#blend-module)
|
||||
7. [Blob-Analysis](#blob-analysis)
|
||||
7. [Blur](#blur-module)
|
||||
8. [Brightness](#brightness-module)
|
||||
9. [Channel](#channel-module)
|
||||
@@ -155,6 +156,20 @@ where `options` is an object with the following properties:
|
||||
* offset: step of image with which current image is to be blended(Two steps back is -2, three steps back is -3 etc; default -2)
|
||||
* func: function used to blend two images (default : function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] })
|
||||
|
||||
## Blob Analysis
|
||||
|
||||
This module uses Opencv.js for detecting and marking blob/region in microscopic images. It requires an opencv.js file to
|
||||
be loaded before using the functionalities which is currently being loaded to the webpage via script.It supports both environments, Node.js and browser for processing.
|
||||
|
||||
As the size of opencv.js file is quite large, the future versions will focus on loading it asynchronously, on demand of the the module to optimise performance.
|
||||
|
||||
#### Usage
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('blob-analysis')
|
||||
.run()
|
||||
```
|
||||
|
||||
## blur-module
|
||||
|
||||
This module is used for applying a Gaussian blur effect.
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
var sequencer;
|
||||
})
|
||||
</script>
|
||||
<script async src="../node_modules/opencv.js/opencv.js" type="text/javascript"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"jsqr": "^1.1.1",
|
||||
"lodash": "^4.17.11",
|
||||
"ndarray": "^1.0.18",
|
||||
"opencv.js": "^1.2.1",
|
||||
"ora": "^3.0.0",
|
||||
"pace": "0.0.4",
|
||||
"puppeteer": "^1.14.0",
|
||||
|
||||
@@ -5,6 +5,7 @@ module.exports = {
|
||||
'add-qr': require('./modules/AddQR'),
|
||||
'average': require('./modules/Average'),
|
||||
'blend': require('./modules/Blend'),
|
||||
'blob-analysis': require('./modules/BlobAnalysis'),
|
||||
'blur': require('./modules/Blur'),
|
||||
'brightness': require('./modules/Brightness'),
|
||||
'canvas-resize': require('./modules/CanvasResize'),
|
||||
|
||||
81
src/modules/BlobAnalysis/BlobAnalysis.js
Normal file
81
src/modules/BlobAnalysis/BlobAnalysis.js
Normal file
@@ -0,0 +1,81 @@
|
||||
module.exports = function(pixels, options, priorStep){
|
||||
|
||||
var $ = require('jquery'); // to make Blob-analysis work for node.js
|
||||
|
||||
var img = $(priorStep.imgElement);
|
||||
if(Object.keys(img).length === 0){
|
||||
img = $(priorStep.options.step.imgElement);
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = pixels.shape[0];
|
||||
canvas.height = pixels.shape[1];
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img[0], 0, 0);
|
||||
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
|
||||
|
||||
let src = cv.matFromImageData(imgData);
|
||||
let dst = new cv.Mat();
|
||||
let gray = new cv.Mat();
|
||||
let opening = new cv.Mat();
|
||||
let imageBg = new cv.Mat();
|
||||
let imageFg = new cv.Mat();
|
||||
let distTrans = new cv.Mat();
|
||||
let unknown = new cv.Mat();
|
||||
let markers = new cv.Mat();
|
||||
|
||||
// gray and threshold image
|
||||
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
|
||||
cv.threshold(gray, gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU);
|
||||
|
||||
// get background
|
||||
let M = cv.Mat.ones(3, 3, cv.CV_8U);
|
||||
cv.erode(gray, gray, M);
|
||||
cv.dilate(gray, opening, M);
|
||||
cv.dilate(opening, imageBg, M, new cv.Point(-1, -1), 3);
|
||||
|
||||
// distance transform
|
||||
cv.distanceTransform(opening, distTrans, cv.DIST_L2, 5);
|
||||
cv.normalize(distTrans, distTrans, 1, 0, cv.NORM_INF);
|
||||
|
||||
// get foreground
|
||||
cv.threshold(distTrans, imageFg, 0.7 * 1, 255, cv.THRESH_BINARY);
|
||||
imageFg.convertTo(imageFg, cv.CV_8U, 1, 0);
|
||||
cv.subtract(imageBg, imageFg, unknown);
|
||||
|
||||
// get connected components markers
|
||||
cv.connectedComponents(imageFg, markers);
|
||||
for (let i = 0; i < markers.rows; i++) {
|
||||
for (let j = 0; j < markers.cols; j++) {
|
||||
markers.intPtr(i, j)[0] = markers.ucharPtr(i, j)[0] + 1;
|
||||
if (unknown.ucharPtr(i, j)[0] == 255) {
|
||||
markers.intPtr(i, j)[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv.cvtColor(src, src, cv.COLOR_RGBA2RGB, 0);
|
||||
cv.watershed(src, markers);
|
||||
|
||||
// draw barriers
|
||||
for (let i = 0; i < markers.rows; i++) {
|
||||
for (let j = 0; j < markers.cols; j++) {
|
||||
if (markers.intPtr(i, j)[0] == -1) {
|
||||
src.ucharPtr(i, j)[0] = 255; // R
|
||||
src.ucharPtr(i, j)[1] = 0; // G
|
||||
src.ucharPtr(i, j)[2] = 0; // B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv.imshow(canvas, src);
|
||||
|
||||
src.delete(); dst.delete(); gray.delete(); opening.delete(); imageBg.delete();
|
||||
imageFg.delete(); distTrans.delete(); unknown.delete(); markers.delete(); M.delete();
|
||||
|
||||
var myImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
pixels.data = myImageData.data;
|
||||
|
||||
return pixels;
|
||||
};
|
||||
43
src/modules/BlobAnalysis/Module.js
Normal file
43
src/modules/BlobAnalysis/Module.js
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
module.exports = function BlobAnalysis(options, UI){
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
var priorStep = this.getStep(-1); // get the previous step to process it
|
||||
|
||||
function extraManipulation(pixels){
|
||||
|
||||
pixels = require('./BlobAnalysis')(pixels, options, priorStep);
|
||||
return pixels;
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype){
|
||||
|
||||
step.output = { src: datauri, format: mimetype};
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
};
|
||||
};
|
||||
4
src/modules/BlobAnalysis/index.js
Normal file
4
src/modules/BlobAnalysis/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
];
|
||||
6
src/modules/BlobAnalysis/info.json
Normal file
6
src/modules/BlobAnalysis/info.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Blob Analysis",
|
||||
"description": "Blob/Region identification for microscopic images.",
|
||||
"inputs": {},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#blob-analysis"
|
||||
}
|
||||
Reference in New Issue
Block a user