How to use canvas to manipulate pixels

Source: Internet
Author: User
This article mainly introduces the use of canvas operation of the method of pixels, the content is very good, and now share to everyone, but also for everyone to make a reference.

Modern browsers support <video> playing video through elements. Most browsers can also access the camera via the Mediadevices.getusermedia () API. But even if these two things are combined, we cannot directly access and manipulate these pixels.

Fortunately, the browser has a canvas API that allows us to draw graphics using JavaScript. In fact, we can draw images from the video itself <canvas> , which allows us to manipulate and display these pixels.

The method you've learned here about how to manipulate pixels will be the basis for you to provide images and videos that deal with any kind of or any source, not just canvas.

Add an image to the canvas

Before we start playing the video, let's look at how to add an image to the canvas.

<p>  <canvas id= "Canvas" class= "video" ></canvas></p>

We created an image element to represent the image to be drawn on the canvas. Alternatively, we can use the image object in JavaScript.

var canvas;var context;function init () {  var image = document.getElementById (' sourceimage ');  Canvas = document.getElementById (' canvas ');  context = Canvas.getcontext (' 2d ');  DrawImage (image);  or  //var image = new Image ();  Image.onload = function () {  //    drawImage (image);  }  //image.src = ' image.jpg ';} function DrawImage (image) {  //Set the canvas the same width and height of the image  Canvas.width = image.width;  canvas.height = image.height;  Context.drawimage (image, 0, 0);} Window.addeventlistener (' Load ', init);

The above code draws the entire image onto the canvas.

View the Paint image on the canvas image on Codepen through the Welling Guzman (@wellingguzman) on the drawing.

Now we can start playing with these pixels!

Update image data

The image data on the canvas allows us to manipulate and change the pixels.

The Data property is a ImageData object that has three properties-width, height, and data/all of which represent something based on the original image. All of these properties are read-only. We are concerned with data, a one-dimensional array represented by an Uint8clampedarray object, containing data for each pixel in the RGBA format.

Although the Data property is read-only, it does not mean that we cannot change its value. This means that we cannot assign another array to this property.

Get the canvas image datavar ImageData = context.getimagedata (0, 0, canvas.width, canvas.height); image.data = new Uint8 Clampedarray (); WRONGIMAGE.DATA[1] = 0; CORRECT

You might ask what value the Uint8clampedarray object represents. The following is a description from the MDN:

An array of type Uint8clampedarray represents an array of 8-bit unsigned integers that are clamped to 0-255, or 0 or 255 if you specify a value that exceeds the range of [0,255]; If you specify a non-integer, the nearest integer is set. The content is initialized to 0. Once established, you can use the object's methods to reference elements in an array, or use standard array index syntax (that is, using parentheses notation)

In short, this array stores values from 0 to 255 at each location, which makes it the perfect solution for the RGBA format, since each part is represented by 0 to 255 values.

RGBA Color

The color can be expressed in RGBA format, which is a combination of red, green and blue. A represents the alpha value of the color opacity.

Each position in the array represents a color (pixel) channel value.

    • The first position is a red value

    • The second position is a green value

    • The third position is a blue value

    • The fourth position is an alpha value

    • The 5th position is the red value of the next pixel

    • The 6th position is the green value of the next pixel

    • The 7th position is the blue value of the next pixel

    • The 8th position is the next pixel alpha value

    • Wait a minute...

If you have a 2x2 image, then we have a 16-bit array (each 2x2 pixel x 4 value).

2x2 Images Zoom Out

The array will resemble the following:

RED                 GREEN                BLUE                 white[255, 0, 0, 255,      0, 255, 0, 255,      0, 0, 255, 255,      255, 255, 255, 255]

Change pixel data

One of the quickest things we can do is set all the pixels to white by changing all RGBA values to 255来.

Use a button to trigger the "effect" var button = document.getElementById (' button '); Button.addeventlistener (' Click ', ON Click), function changetowhite (data) {for  (var i = 0; i < data.length; i++) {    data[i] = 255;  }} function OnClick () {  var imageData = context.getimagedata (0, 0, canvas.width, canvas.height);  Changetowhite (imagedata.data);  Update the canvas with the new data  context.putimagedata (imageData, 0, 0);}

The data is passed as a reference, which means that any changes we make to it will change the value of the passed parameter.

Invert color

The good effect of not requiring too much computation is to invert the color of the image.

You can use the XOR operator (^) or this formula 255-value (the value must be between 0-255) to invert the color value.

function Invertcolors (data) {for  (var i = 0; i < data.length; i+= 4) {    Data[i] = data[i] ^ 255;//Invert red< C2/>DATA[I+1] = data[i+1] ^ 255; Invert Green    data[i+2] = data[i+2] ^ 255;//Invert Blue  }}function OnClick () {  var imageData = Context.get ImageData (0, 0, canvas.width, canvas.height);  Invertcolors (imagedata.data);  Update the canvas with the new data  context.putimagedata (imageData, 0, 0);}

We are increasing the loop by 4 instead of 1 as we did before, so we can populate the 4 elements in the array from pixels to pixels, per pixel.

The alpha value has no effect on invert color, so we skip it.

Brightness and contrast

Use the following formula to adjust the brightness of the image: NewValue = currentvalue + 255 * (brightness/100).

    1. Brightness must be between 100 and 100

    2. CurrentValue is the current light value of red, green, or blue.

    3. NewValue is the result of the current color light plus brightness

    4. Adjusting the contrast of the image can be done with this formula:

Factor = (259 * (contrast + 255))/(255 * (259-contrast)) color = Getpixelcolor (x, y) newred   = Truncate (Factor * (Red (color)   -+) Newgreen = Truncate (Factor * (Green)-+) Newblue  = Truncate (factor * (Blue color)  -12 8) + 128)

The primary calculation is to get the contrast factor that will be applied to each color value. Truncation is a function that ensures that values remain between 0 and 255.

Let's write these functions into javascript:

function applybrightness (data, brightness) {for  (var i = 0; i < data.length; i+= 4) {    Data[i] + = 255 * (Bright NESS/100);    DATA[I+1] + = 255 * (brightness/100);    DATA[I+2] + = 255 * (brightness/100);  }} function Truncatecolor (value) {  if (value < 0) {    value = 0;  } else if (value > 255) {    value = 255;
  }  return value;} function Applycontrast (data, contrast) {  var factor = (259.0 * (contrast + 255.0))/(255.0 * (259.0-contrast)); 
  for (var i = 0; i < data.length; i+= 4) {    Data[i] = Truncatecolor (Factor * (Data[i]-128.0) + 128.0);    Data[i+1] = Truncatecolor (Factor * (Data[i+1]-128.0) + 128.0);    DATA[I+2] = Truncatecolor (Factor * (Data[i+2]-128.0) + 128.0);}  }

In this case, you do not need the Truncatecolor function, because Uint8clampedarray truncates the values, but in order to translate the algorithm that we added in it.

One thing to keep in mind is that if you apply brightness or contrast, the image data is overwritten and cannot go back to its previous state. If we want to reset to the original state, the original image data must be stored separately for reference. It is helpful to keep the image variable accessible to other functions, because you can use the image to redraw the canvas and the original image.

var image = document.getElementById (' sourceimage '), function Redrawimage () {  context.drawimage (image, 0, 0);}

Using video

To make it suitable for video, we will use our initial image script and HTML code and make some minor changes.

Html

Change the image element of the video element by replacing the following line:

... with this:

<video src></video>

Javascript

Replace this line:

var image = document.getElementById (' sourceimage ');

... Add this line:

var video = document.getElementById (' Sourcevideo ');

To start processing the video, we have to wait until the video is ready to play.

Video.addeventlistener (' Canplay ', function () {    //Set the canvas the same width and height of the video    Canvas.wi DTH = Video.videowidth;    Canvas.height = video.videoheight;        Play the video    video.play ();    Start drawing the Frames      drawframe (video);});

When there is enough data to play the media, the event plays at least a few frames.

We can't see any video displayed on the canvas because we only show the first frame. We must execute the Drawframe every n milliseconds to keep up with the video frame rate.

Inside the Drawframe, we call Drawframe again every 10ms.

function Drawframe (video) {  context.drawimage (video, 0, 0);  SetTimeout (function () {    drawframe (video);  }, 10);}

After executing drawframe, we create a loop that executes drawframe once every 10ms-enough time to keep the video in sync in the canvas.

Add an effect to a video

We can invert the color using the same function we created earlier:

function Invertcolors (data) {for  (var i = 0; i < data.length; i+= 4) {    Data[i] = data[i] ^ 255;//Invert red< C7/>DATA[I+1] = data[i+1] ^ 255; Invert Green    data[i+2] = data[i+2] ^ 255;//Invert Blue  }}

and add it to the Drawframe function:

function Drawframe (video) {  context.drawimage (video, 0, 0);  var imageData = context.getimagedata (0, 0, canvas.width, canvas.height);  Invertcolors (imagedata.data);  Context.putimagedata (imageData, 0, 0);  SetTimeout (function () {    drawframe (video);  }, 10);}

We can add a button and toggle the effect:

function Drawframe (video) {  context.drawimage (video, 0, 0);  if (applyeffect) {    var imageData = context.getimagedata (0, 0, canvas.width, canvas.height);    Invertcolors (imagedata.data);    Context.putimagedata (imageData, 0, 0);  }  SetTimeout (function () {    drawframe (video);  }, 10);}

Using the camera

We will keep the same code we used for the video, except that we will use Mediadevices.getusermedia to change the video stream from the file to the camera stream.

Mediadevices.getusermedia is a new API that discards the previous API Mediadevices.getusermedia (). Browsers still support older versions, and some browsers do not support new versions, we must resort to Polyfill to ensure that browsers support one of them.

First, remove the SRC attribute from the video element:

<video><code></pre><pre><code>//Set The source of the video to the camera streamfunction I Nitcamera (stream) {    video.src = window. Url.createobjecturl (stream);} if (navigator.mediaDevices.getUserMedia) {  Navigator.mediaDevices.getUserMedia ({video:true, audio:false})    . Then (Initcamera)    . catch (Console.error)  );}

Live Demo

Effect

So far, everything we've covered is the basis we need to create different effects for videos or images. We can use a lot of different effects by converting each color independently.

Gray Scale

Converting colors to grayscale can be done in different ways using different formulas/techniques to avoid getting into too deep a problem I will show you five formulas based on the GIMP desaturate tool de-saturation tools and Luma:

Gray = 0.21R + 0.72G + 0.07B//Luminositygray = (r + G + B) ÷3//Average Brightnessgray = 0.299R + 0.587G + 0.114B//R ec601 Standardgray = 0.2126R + 0.7152G + 0.0722B//ITU-R bt.709 Standardgray = 0.2627R + 0.6780G + 0.0593B//ITU-R bt.21 XX standard

We want to use these formulas to find the luminance level for each pixel color. The value ranges from 0 (black) to 255 (white). These values create a grayscale (black-and-white) effect.

This means that the brightest color will be closest to 255, the darkest color closest to 0.

Live Demo

Double tone

The difference between a duotone effect and a grayscale effect is that two colors are used. In grayscale, you have a gradient from black to white, and in two tones, you can have a ramp from any color to any other color (from blue to pink).

Using the intensity value of grayscale, we can replace it with a gradient value.

We need to create a gradient from Colora to Colorb.

function Creategradient (Colora, Colorb) {//Values of the gradient from Colora to colorb var gradient = [];  The maximum color value is 255 var maxValue = 255;  Convert the hex color values to RGB object var from = Getrgbcolor (Colora);  var to = Getrgbcolor (Colorb);  Creates colors from color A to color B for (var i = 0; I <= maxValue; i++) {//Intensityb'll go from 0 to  255//Intensitya would go from 255 to 0//Intensitya would decrease intensity while instensityb would increase//  What's this means was that Colora would start solid and slowly transform into colorb    Transparency of color A would increase and the transparency of color B would decrease var intensityb = i;    var Intensitya = Maxvalue-intensityb; The formula below combines the color based on their intensity//(Intensitya * colora + intensityb * colorb)/M Axvalue Gradient[i] = {r: (INTENSITYA*FROM.R + INTENSITYB*TO.R)/mAxvalue, G: (INTENSITYA*FROM.G + intensityb*to.g)/MaxValue, B: (Intensitya*from.b + intensityb*to.b)/Maxvalu  e}; } return gradient;}  Helper function to convert 6digit hex values to a RGB color objectfunction getrgbcolor (hex) {var colorvalue;  if (hex[0] = = = ' # ') {hex = HEX.SUBSTR (1);  } ColorValue = parseint (hex, 16); return {R:colorvalue >>, G: (ColorValue >> 8) & 255, B:colorvalue & 255}}

In short, we create a set of color values from color A, reducing the intensity while going to color B and increasing strength.

From #0096ff to #ff00f0

var gradients = [  {r:32, g:144, b:254},  {r:41, g:125, b:253}, {r:65,  g:112, b:251},  {r:91, g:96 , b:250},  {r:118, g:81, b:248},  {r:145, g:65, b:246}, {r:172,  g:49, b:245},  {r:197, g:34, B:2 (),  {r:220, g:21, b:242},  {r:241, g:22, b:242},];

Scaling the representation of a color transition

There is an example of a gradient of 10 color values from #0096ff to #ff00f0.

Grayscale representation of color transitions

Now that we have a grayscale representation of the image, we can use it to map it to a duotone gradient value.

The Duotone gradient has a colors while the grayscale have also the colors ranging from black (0) to White (255). That means a grayscale color value would map to a gradient element index.

var gradientcolors = creategradient (' #0096ff ', ' #ff00f0 '), var imageData = context.getimagedata (0, 0, Canvas.width, Canvas.height); applygradient (Imagedata.data); for (var i = 0; i < data.length; i + = 4) {  //Get the each channel col or value  var redvalue = data[i];  var greenvalue = data[i+1];  var bluevalue = data[i+2];  Mapping the color values to the gradient index  //replacing the grayscale color value with a color for the Duotone Gradient  data[i] = GRADIENTCOLORS[REDVALUE].R;  DATA[I+1] = GRADIENTCOLORS[GREENVALUE].G;  DATA[I+2] = gradientcolors[bluevalue].b;  DATA[I+3] = 255;}

Live Demo

Conclusion

This topic can be more in-depth or explain more influence. The lesson for you is to find different algorithms that can be applied to these skeleton examples.

Understanding the structure of the pixel on the canvas will allow you to create an unlimited number of effects, such as sepia, process color, green screen effect, image flicker/glitch, etc.

You can even create an effect instantly without using an image or video

The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.