I have a super simple need of OCR.
My application allows creating image from text. Its very simple. People choose a font face, bold or not, and size.
So they get outputs like this, ignoring the border:
I wanted to create a very simple OCR to read these. I thought of this approach:
In the same way I generate an image for the message. I should generate an image for each character. Then I go through and try to match each character image to the black occourances in the canvas. Is this right approach?
The method I use to draw element to image is this copy paste example here: MDN :: Drawing DOM objects into a canvas
Ok, another couple of tries...
Another method that's simpler than OCR: use Steganography to embed the text message as part of the image itself. Here's a script that uses the alpha channel of an image to store text: http://www.peter-eigenschink.at/projects/steganographyjs/index.html
You can try this "home brewed" OCR solution...but I have doubts about its effectiveness.
Use the clipping form of context.drawImage to draw just the message-text area of your image on the canvas.
Use context.getImageData to grab the pixel information.
Examine each vertical column starting from the left until you find an opaque pixel (this is the left side of the first letter).
Continue examining each vertical column until you find a column with all transparent pixels (this is the right side of the first letter).
Resize a second canvas to exactly contain the discovered letter and drawImage just the first letter to a second canvas.
Set globalCompositeOperation='destination-out' so that any new drawing will erase any existing drawings where the new & old overlap.
fillText the letter "A" on the second canvas.
Use context.getImageData to grab the pixel information on the second canvas.
Count the opaque pixels on the second canvas.
If the opaque pixel count is high, they you probably haven't matched the letter A, so repeat steps 5-9 with the letter B.
If the opaque pixel count is low, then you may have found the letter A.
If the opaque pixel count is medium-low, you may have found the letter A but the 2 A's are not quite aligned. Repeat steps 5-9 but offset the A in step#7 by 1 pixel horizontally or vertically. Continue offsetting the A in 1 pixel offsets and see if the opaque pixel count becomes low.
If step#12 doesn't produce a low pixel count, continue with the letter B,C,etc and repeat steps 5-9.
When you're done discovering the first letter, go back to step#1 and only draw the message-text with an offset that excludes the first letter.
OCR is always complex and often inaccurate.
I hate to wave you off of a solution, but don't use OCR for your purpose
Simple and effective solution...
Put your message in the image's file name.
Solution found - GOCR.js - https://github.com/antimatter15/gocr.js/tree/d820e0651cf819e9649a837d83125724a2c1cc37
download gocr.js
decide if you want to go from WebWorker, or mainthread
worker
In the worker put this code:
importScripts(gocr.js)
GOCR(aImgData)
where aImgData is, take an image, load it, draw it to canvas, then send the data to the webworker. (see mainthread method)
mainthread
<script src="gocr.js">
<script>
var img = new Image()
img.onerror = function() {
console.error('failed')
}
img.onload = function() {
var can = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
can.width = img.width;
can.height = img.height;
var ctx = can.getContext('2d')
ctx.drawImage(img, 0, 0)
// to use this in a worker, do ctx.getImageData(0, 0, img.width, img.height), then transfer the image data to the WebWorker
var text = GOCR(can);
}
</script>
Related
I'm two days into js,html and css programming. So very newbie!
Following and building upon this TUTORIAL
Q1: How can I add this male into the background (see figuere 1.) and prohibit any strokes outside of the borders?
Adding image to background was no biggy!
function make_base()
{
base_image = new Image();
base_image.src = 'img/bmapFront.gif';
base_image.onload = function(){
context.drawImage(base_image, 0,0);
}
}
There is a context.clip function, not sure if I can use pixel form as clipping path. Making tons of "image substractions" isn't the best way.
Any suggestions
Edit:
Did the Job for me: VeryHelpful
var frontPath = new Path2D ("M 133.41,17.00 C 141.37,2.41 160.66, !VERY LONG! ")
context.clip(frontPath);
Messy strokes!
He should look like this. Then I want to save him.
Although there is such a thing as ctx.clip(), this is sometimes not what's wanted as it's impractical to use a path.
The solution that I like involves creating a virtual empty canvas onto which you draw your pixel image. Through various manipulations, like using ctx.getImageData and similar to make sure you only get one kind of color or apply other filters only once, you can obtain an image that seems to be empty (alpha of 0, mostly) in the places where you want to clip other images or paths out.
At that point, you'd use ctx.globalCompositeOperation = 'source-atop', or pick another one you might want to use from mdn's list of globalCompositeOperations.
At this point, you can just draw this virtual canvas image onto the main canvas
If you click Run code snippet in this link, it shows a cool usage of <canvas> where you can "cut-out" part of the image (just drag your mouse on the image to "cut"). I'm just curious if there is any way to save the resulting "cut-out" part of the image, as a transparent PNG (i.e. everything that is white in the canvas would be transparent).
If anyone can point me in the right direction (or tell me it's not doable), I'd appreciate it.
Yes, there is a way. Use canvas context.getImageData to get image raw data-array. Do with it(raw data) what you need(make transparent any pixel you need), and then use context.putImageData to render data on canvas. Then use var data = canvas.toDataURL("image/png") to get image data. And then you can do so: image.src = data;
Use this link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData for more info
Here's a quick tour showing how to crop & save a user-dragged cutout of an image:
Draw the image on the canvas.
Listen to mouse events and let the user define the region they want to cut out by continuously connecting new lines to the current mouse position.
Save every mouse point from #2 in an array.
When the user has finished defining their cutout region:
Clear the canvas.
Draw and fill the cutout area using the saved points in the arry.
Set context.globalCompositeOperation='source-in'. This mode will cause any new drawings to appear only where the newly drawn pixels and the existing pixels overlap and every thing else is made transparent. In common terms: New pixels will be "clipped" into the user defined cutout and new pixels will not appear outside the cutout.
Redraw the image.
The result is the second drawing of the image will appear only inside the user defined cutout. Everything else will be transparent.
Finally, you can use var url=canvasElement.toDataURL to save the cropped canvas image into a .png dataURL. If you then want an actual image from this dataURL you can var img=new Image() and set the img.src=url.
After searching the web for just over an hour, I have not found any luck.
I am wondering if it is possible, if so how do I create a transparent image on a js canvas not to be considered as a rectangle, rather only the visible area of it.
For example if you click in a transparent spot on the png the script does not considered that part of the object.
Thank you :)
Yes, you can get info about every pixel on the canvas using context.getImageData
A Demo: http://jsfiddle.net/m1erickson/tMmzc/
This code will get an array containing info about every pixel on the canvas:
var data=ctx.getImageData(0,0,canvas.width,canvas.height).data;
The data array is organized with 4 sequential element representing the red,green,blue & alpha(opacity) information about one pixel.
The data array's elements #0-3 have the top-left pixel's r,g,b,a info.
The data array's elements #4-7 have the next rightward pixel's r,g,b,a info.
...and so on...
Therefore, given the mouse position on the canvas you can fetch that pixel's alpha info. If the alpha value is zero then that pixel is transparent.
This code will read the alpha value under the mouse and determine if it's transparent:
var isTransparent = data[(mouseY*canvas.width+mouseX)*4+3]>0;
I just created a fancy canvas effect using cheap motion blur
ctx.fillStyle = "rgba(255,255,255,0.2)";
ctx.fillRect(0,0,canvas.width,canvas.height);
Now i want to do the same, but with transparent background. Is there any way to do something like that? I'm playing with globalAlpha, but this is probably a wrong way.
PS: Google really don't like me today
Here's a more performance friendly way of doing it, it requires an invisible buffer and a visible canvas.
buffer.save();
buffer.globalCompositeOperation = 'copy';
buffer.globalAlpha = 0.2;
buffer.drawImage(screen.canvas, 0, 0, screen.canvas.width, screen.canvas.height);
buffer.restore();
Basically you draw your objs to the buffer, which being invisible is very fast, then draw it to the screen. Then you replace clearing the buffer with copying the last frame onto the buffer using the global alpha, and globalCompositeOperation 'copy' to make the buffer into a semi-transparent version of the previous frame.
You can create an effect like this by using globalAlpha and two different canvas objects: one for the foreground, and one for the background. For example, with the following canvas elements:
<canvas id="bg" width="256" height="256"></canvas>
<canvas id="fg" width="256" height="256"></canvas>
You could copy draw both a background texture and a motion blurred copied of foreground like so:
bg.globalAlpha = 0.1;
bg.fillStyle = bgPattern;
bg.fillRect(0, 0, bgCanvas.width, bgCanvas.height);
bg.globalAlpha = 0.3;
bg.drawImage(fgCanvas, 0, 0);
Here is a jsFiddle example of this.
OP asked how to do this with an HTML background. Since you can't keep a copy of the background, you have to hold onto copies of previous frames, and draw all of them at various alphas each frame. Nostalgia: the old 3dfx Voodoo 5 video card had a hardware feature called a "t-buffer", which basically let you do this technique with hardware acceleration.
Here is a jsFiddle example of that style. This is nowhere near as performant as the previous method, though.
What you are doing in the example is partially clear the screen with a semi transparent color, but as it is, you will always gonna to "add" to the alpha channel up to 1 (no transparency).
To have this working with transparent canvas (so you can see what lies below) you should subtract the alpha value instead of adding, but I don't know a way to do this with the available tools, except running all the pixels one by one and decrease the alpha value, but this will be really, really slow.
If you are keeping track of the entities on screen you can do this by spawning new entities as the mouse moves and then setting their alpha level in a tween down to zero. Once they reach zero alpha, remove the entity from memory.
This requires multiple drawing and will slow down rendering if you crank it up too much. Obviously the two-canvas approach is the simplest and cheapest from a render performance perspective but it doesn't allow you to control other features like making the "particles" move erratically or apply physics to them!
Is there any trick to determine if user clicks on given element rendered in canvas? For example I'm displaying rhombus from .png file with transparent background and i want to know if user click inside or outside that figure (like mouse-element collision).
There is no concept of individual elements in a canvas - it is simply just an area that you're drawing pixels onto. SVG on the other hand is made up of elements which you can then bind events to. However there are a few approaches you can take to add click events to canvas:
Position an html element that overlays the area on the canvas you want to be clickable. A for a rectangular area or an image map for something more irregular.
Use separate canvases for each element that you want to be clickable.
CAKE - I haven't used this myself, but it's description is "SVG sans the XML". This may cover your needs. Demos here http://glimr.rubyforge.org/cake/canvas.html#EditableCurve
One idea is to draw the image to a temporary canvas, then use getImageDate() to receive data for the pixel you are interested in, and check if its alpha value is 0 ( = transparent).
The following is a sketch of a solution. It is assumed that...
x and y are the coordinates of the mouse click event
you are looping over gameObjects, the current object being stored in the variable gameObject
the game object has been initialized with an image, x and y coordinates
The following code would then check whether the click was on a transparent area:
var tempCanvas = document.createElement('canvas');
if (tempCanvas.getContext) {
tempContext = tempCanvas.getContext('2d');
}
tempContext.drawImage(gameObject.img, 0, 0);
var imgd = tempContext.getImageData(x - gameObject.x, y - gameObject.y, 1, 1);
var pix = imgd.data;
if (pix[3] == 0) {
// user clicked on transparent part of the image!
}
Note: This is probably quite inefficient. I'm sure someone can come up with a better solution.
I have solve this problem using kintech.js, tutorials and examples can be found: http://www.html5canvastutorials.com/kineticjs/html5-canvas-drag-and-drop-tutorial/