Как превратить прямоугольник в круг - PullRequest
0 голосов
/ 23 октября 2018

Я хочу превратить прямоугольное изображение в круг, используя элемент HTMLCanvas.(Наконец, мне нужна только верхняя половина круга, но это можно легко сделать, разрезав получившийся круг пополам.)

Из этого

Rectangle

К этому

circle

Моя идея состояла в том, чтобы сделать простое построчное преобразование.Пока у меня есть только базовая логика рисования, но я полностью потерян с математикой для преобразования.

<!DOCTYPE html>
<body>
    <canvas id="canvas"></canvas>
</body>

<script type="text/javascript">
var img = new Image();
img.onload = function init() {
    var img = this;
    var imgH = img.height;
    var imgW = img.width;

    // make the canvas the same size as the image.
    var c = document.getElementById("canvas");
    c.width = imgW;
    c.height = imgH;

    var ctx = c.getContext("2d");
    var halfHeight = imgH/2;

    // draw the upper part
    // line by line
    for(var i = 0; i < halfHeight; i++) {
        // I'm totally lost here.

        // current output without transformation
        ctx.drawImage(img, 0, i, imgW, 1, 0, i, imgW, 1);
    }

    // add the second half which must not be transformed
    ctx.drawImage(img, 0, halfHeight, imgW, halfHeight, 0, halfHeight, imgW, halfHeight);
};
img.src = "https://i.stack.imgur.com/52TjZ.png";

</script>
</html>

Скрипка https://jsfiddle.net/kirschkern/amq7t6ru/2/

(мне это нужно в чистом JS и2d. Нет three.js, нет webgl.)

Любая помощь высоко ценится.

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Я не знаю много о Javascript, но так как это кажется больше математическим вопросом, я сделаю мой выстрел.

Замените строки

    // I'm totally lost here.

    // current output without transformation
    ctx.drawImage(img, 0, i, imgW, 1, 0, i, imgW, 1);

на

    var xMargin = -Math.sqrt(1-Math.pow((i-halfHeight)/halfHeight,2))*imgW/2+imgW/2;
    ctx.drawImage(img, 0, i, imgW, 1, xMargin, i, imgW-(2*xMargin), 1);

Это искажает верхнюю половину изображения в виде эллипса (круг будет работать, только если ваше входное изображение будет квадратным), как это:

Image with the upper half distorted

Решает ли это ваш вопрос?

Объяснение

Я взял уравнение сдвинутого эллипса из Википедии и установил c1 и a равным imgW/2 и c2 и b до imgH / 2 .Взяв i за y позвольте мне вычислить x ;Я сохранил одно из решений как xMargin.Ширина изображения при заданной вертикальной координате будет равна исходной ширине минус двойное поле.

В конце я подал drawImage() этими входами, см. Документацию .

0 голосов
/ 23 октября 2018

Простой 2D JavaScript не имеет примитивов для искажения таких изображений.Так что простого drawImage будет недостаточно.

Что вы можете сделать, это приблизительные вещи.Напишите функцию, которая для каждой точки искаженного изображения (с кружком) вычисляет соответствующую позицию исходного изображения.Затем вы можете выполнить одно из четырех действий в порядке увеличения усилия и получающегося качества.

  1. Выполните итерацию по всем пикселям в целевом изображении и найдите соответствующее значение пикселя в исходном изображении.
  2. Как и раньше, но с субдискретизацией: занять несколько позиций внутри квадрата исходного пикселя и усреднить соответствующие цвета для более плавного внешнего вида.
  3. Приблизительно аффинное преобразование в данной точке (для этоговам, вероятно, понадобятся частичные производные вашей функции отображения) и используйте ее для рисования аффинно преобразованного изображения.
  4. То же, что 3, но с проективными, а не аффинными преобразованиями.Это, возможно, сделало бы его 3D в его формулировке.
  5. Как 1 или 2, но реализовать все это в WebGL как фрагментный шейдер.Я знаю, что вы сказали, что не хотите этого, но с точки зрения производительности и получающегося качества это должно дать наилучшие результаты.
...