Использование C #, что является эквивалентным способом сжатия и улучшения рукописных заметок [duplicate]

Что вы должны знать о this

this (иначе говоря, «контекст») - это специальное ключевое слово внутри каждой функции, и его значение зависит только от , как была вызвана функция, а не как / когда / где она была определена. Лексические области не затрагиваются, как и другие переменные. Вот несколько примеров:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

Чтобы узнать больше о this, просмотрите документацию MDN .


Как сделать обратитесь к правильному this

Не используйте this

Фактически вы не хотите иметь доступ к this в частности, но объект, на который он ссылается на . Вот почему простое решение - просто создать новую переменную, которая также относится к этому объекту. Переменная может иметь любое имя, но общие - self и that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

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

Явно установить this обратного вызова - часть 1

Возможно, у вас есть не контролируйте значение this, потому что его значение устанавливается автоматически, но на самом деле это не так.

Каждая функция имеет метод .bind [docs] , который возвращает новую функцию с this, привязанную к значению. Функция имеет то же поведение, что и тот, который вы назвали .bind, только то, что this было установлено вами. Независимо от того, как и когда эта функция вызывается, this всегда будет ссылаться на переданное значение.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

В этом случае мы привязываем обратный вызов this к значению MyConstructor 's this.

Примечание. При связывании контекста для jQuery вместо этого используйте jQuery.proxy [docs] . Причина этого заключается в том, что вам не нужно сохранять ссылку на функцию при отмене обратного вызова события. jQuery обрабатывает это внутренне.

ECMAScript 6: Используйте функции стрелок

В ECMAScript 6 представлены функции стрелок , которые можно рассматривать как лямбда-функции. У них нет собственной привязки this. Вместо этого this просматривается в области видимости как обычная переменная. Это означает, что вам не нужно называть .bind. Это не единственное особое поведение, которое у них есть. Дополнительную информацию см. В документации MDN.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Установите this обратного вызова - часть 2

Некоторые функции / методы, которые принимают обратные вызовы, также принимают значение, к которому должен обращаться обратный вызов this. Это в основном то же самое, что и привязывать его самостоятельно, но функция / метод делает это за вас. Array#map [docs] - такой метод. Его подпись такова:

array.map(callback[, thisArg])

Первый аргумент - это обратный вызов, а второй аргумент - значение this. Вот надуманный пример:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Примечание. Можно ли передать значение для this, как правило, упоминается в документации этой функции / метода. Например, метод $.ajax jQuery [docs] описывает параметр, называемый context:

Этот объект станет контекстом всех обратных вызовов, связанных с Ajax.


Общая проблема: использование объектных методов в качестве обработчиков обратных вызовов / событий

Еще одно распространенное проявление этой проблемы - когда объектный метод используется как обработчик обратного вызова / события , Функции являются первоклассными гражданами в JavaScript, а термин «метод» - просто разговорный термин для функции, которая является значением свойства объекта. Но эта функция не имеет конкретной ссылки на ее «содержащий» объект.

Рассмотрим следующий пример:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

Функция this.method назначается как обработчик события click , но если щелкнуть document.body, зарегистрированное значение будет undefined, потому что внутри обработчика события this ссылается на document.body, а не на экземпляр Foo. Как уже упоминалось в начале, то, что относится к [49], зависит от того, как называется функция, а не от того, как она определена. Если код выглядит следующим образом, может быть более очевидно, что функция не имеет неявной ссылки на объект:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

Решение такое же, как указано выше: если доступно, используйте .bind явно привязать this к определенному значению

document.body.onclick = this.method.bind(this);

или явно вызвать функцию как «метод» объекта, используя анонимную функцию в качестве обработчика обратного вызова / события и назначить object (this) к другой переменной:

var self = this;
document.body.onclick = function() {
    self.method();
};

или использовать функцию стрелки:

document.body.onclick = () => this.method();
0
задан Spektre 6 December 2015 в 15:34
поделиться

2 ответа

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

Вот результат для Gamma = 6.27 и Contrast = +1.04:

Вот код, который я использовал:

using System.Drawing.Imaging;
..

public static Bitmap ApplyGamma(Bitmap bmp0, float gamma, float contrast)
{

    Bitmap bmp1 = new Bitmap(bmp0.Width, bmp0.Height);
    using (Graphics g = Graphics.FromImage(bmp1))
    {
        ColorMatrix colorMatrix = new ColorMatrix(new float[][] 
                {
                    new float[] {contrast, 0, 0, 0, 0},
                    new float[] {0,contrast, 0, 0, 0},
                    new float[] {0, 0, contrast, 0, 0},
                    new float[] {0, 0, 0, 1, 0},
                    new float[] {0, 0, 0, 0, 1}
                });


        ImageAttributes attributes = new ImageAttributes();
        attributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default,
                                               ColorAdjustType.Bitmap);
        attributes.SetGamma(gamma, ColorAdjustType.Bitmap);
        g.DrawImage(bmp0, new Rectangle(0, 0, bmp0.Width, bmp0.Height),
                    0, 0, bmp0.Width, bmp0.Height, GraphicsUnit.Pixel, attributes);
    }
    return bmp1;
}

функция использует две переменные и две TrackBars вместе с двумя Labels:

float gamma = 1f ;
float contrast = 1f;

private void trackBar1_Scroll(object sender, EventArgs e)
{
    gamma = 1f * trackBar1.Value / 100f;
    label1.Text = gamma.ToString("#0.00");
    pictureBox1.Image = ApplyGamma(originalImage, gamma, contrast);
}


private void trackBar2_Scroll(object sender, EventArgs e)
{
    contrast = 1f * trackBar2.Value / 1000f;
    label2.Text = contrast.ToString("#0.00");
    pictureBox1.Image = ApplyGamma(originalImage, gamma, contrast);
}

Обратите внимание, что я утечка Bitmaps; это просто для тестирования; -)

2
ответ дан TaW 21 August 2018 в 19:12
поделиться

Я использую этот код (C ++):

void picture::enhance_range()
    {
    int i,x,y,a0[4],min[4],max,n,c0,c1,q,c;
    if (xs<1) return;
    if (ys<1) return;

    n=0;    // dimensions to interpolate
    if (pf==_pf_s   ) { n=1; c0=0; c1=127*3; }
    if (pf==_pf_u   ) { n=1; c0=0; c1=255*3; }
    if (pf==_pf_ss  ) { n=2; c0=0; c1=32767; }
    if (pf==_pf_uu  ) { n=2; c0=0; c1=65535; }
    if (pf==_pf_rgba) { n=4; c0=0; c1=  255; } // this is your image pixel format so ignore the other pf statements

    // find min,max intensities
    dec_color(a0,p[0][0],pf);
    for (i=0;i<n;i++) min[i]=a0[i]; max=0;
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        dec_color(a0,p[y][x],pf); // this just unpack pixel color p[][] to a0[4]={r,g,b,a}
        for (q=0,i=0;i<n;i++)
            {
            c=a0[i]; if (c<0) c=-c;
            if (min[i]>c) min[i]=c;
            if (max<c) max=c;
            }
        }
    // change dynamic range to max
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        dec_color(a0,p[y][x],pf);
        for (i=0;i<n;i++) a0[i]=c0+(((a0[i]-min[i])*(c1-c0))/(max-min[i]+1));
//      for (i=0;i<n;i++) if (a0[i]<c0) a0[i]=c0; // clamp if needed
//      for (i=0;i<n;i++) if (a0[i]>c1) a0[i]=c1; // clamp if needed
        enc_color(a0,p[y][x],pf); // this just pack a0[4]={r,g,b,a} to pixel color p[][]
        }
    }

где:

  • pf - это текущий формат пикселя в вашем случае pf=_pf_rgba, который является просто перечислением константа
  • xs,ys - разрешение изображения
  • p[y][x] - прямой доступ к пикселю изображения
  • enc_color,dec_color просто упаковывать / распаковывать цветовые компоненты для нужного пикселя format

Это результат:

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

min=181;
max=254;

Итак, если вы берете каждый пиксель и масштабируетесь до макс <0,255>, вам нужно сделать что-то вроде:

color=(color-min)*255/(max-min);

для каждого пикселя изображения, и это все.

[Примечания]

Как заметил @RosaGronchi, ваш текущий подход медленный из-за использования getpixel,setpixel вместо этого использует строки сканирования должно быть в несколько тысяч раз быстрее).

. Еще один недостаток вашего подхода - что вы просто бинаризуете изображение, теряя все визуализированное сглаживание текста ...

1
ответ дан Community 21 August 2018 в 19:12
поделиться
  • 1
    , что должно быть в несколько тысяч раз быстрее . Это звучит довольно оптимистично для меня. – TaW 6 December 2015 в 18:37
  • 2
    @TaW совсем нет, если закодировано правильно ... каждый setpixel или getpixel вызывает много GDI-вызовов, проверяющих для bouns, pixelformat, coverions и многое другое ... Свойство ScanLine делает это но только один раз в строке, и если запомнить это только один раз в строке на изображение / изменение размера и к нему можно получить доступ несколько раз после ... при тяжелом доступе к пикселам обычная скорость увеличивается примерно в 10000x раза (например, для 3D-рендеринга или заполнения SW алгоритмы) ... но должны быть закодированы правильно ... – Spektre 6 December 2015 в 19:19
  • 3
    Ну, в последний раз, когда я сжимаю Lockbits и get / setPixel был примерно в 20 раз быстрее. Много, но отнюдь не тысячи. Но это не то же самое, что и ваш код. – TaW 6 December 2015 в 19:24
  • 4
    @Taw Это зависит от того, насколько вы фактически используете getpiel, setpixel вместо прямого доступа к пикселям ... против количества альтернативных вызовов GDI. Если getpixel, setpixel, на которые вы ссылаетесь, не являются GDI, тогда это целая другая тема. – Spektre 6 December 2015 в 19:34
  • 5
    Я сравнивал использование GDI + Get / SetPixel от C # angainst LockBits. – TaW 6 December 2015 в 19:35
Другие вопросы по тегам:

Похожие вопросы: