From: Martin Renold Date: Sat, 6 Aug 2011 11:54:27 +0000 (+0200) Subject: strokemap: thresholds tuning X-Git-Url: http://git.sourceforge.jp/view?a=commitdiff_plain;h=08c475d632edbd1b465a51780116fc926a2c05ed;p=mypaint-anime%2Fmaster.git strokemap: thresholds tuning Replace ugly thresholding code with more ugly thresholding code. The previous code did compare the difference of premultiplied color components, with the result that white strokes had more weight than black strokes. This at least is fixed now, and hopefully everything is better tuned, too. --- diff --git a/lib/pixops.hpp b/lib/pixops.hpp index 4c72274..9c4a0dd 100644 --- a/lib/pixops.hpp +++ b/lib/pixops.hpp @@ -388,3 +388,78 @@ void tile_convert_rgba8_to_rgba16(PyObject * src, PyObject * dst) { } } } + +// used in strokemap.py +// +// Calculates a 1-bit bitmap of the stroke shape using two snapshots +// of the layer (the layer before and after the stroke). +// +// If the alpha increases a lot, we want the stroke to appear in +// the strokemap, even if the color did not change. If the alpha +// decreases a lot, we want to ignore the stroke (eraser). If +// the alpha decreases just a little, but the color changes a +// lot (eg. heavy smudging or watercolor brushes) we want the +// stroke still to be pickable. +// +// If the layer alpha was (near) zero, we record the stroke even if it +// is barely visible. This gives a bigger target to point-and-select. +// +void tile_perceptual_change_strokemap(PyObject * a, PyObject * b, PyObject * res) { + + assert(PyArray_TYPE(a) == NPY_UINT16); + assert(PyArray_TYPE(b) == NPY_UINT16); + assert(PyArray_TYPE(res) == NPY_UINT8); + assert(PyArray_ISCARRAY(a)); + assert(PyArray_ISCARRAY(b)); + assert(PyArray_ISCARRAY(res)); + + uint16_t * a_p = (uint16_t*)PyArray_DATA(a); + uint16_t * b_p = (uint16_t*)PyArray_DATA(b); + uint8_t * res_p = (uint8_t*)PyArray_DATA(res); + + for (int y=0; y MAX(alpha_old, alpha_new)/16; + + int32_t alpha_diff = alpha_new - alpha_old; // no abs() here (ignore erasers) + // We check the alpha increase relative to the previous alpha. + bool is_perceptual_alpha_increase = alpha_diff > (1<<15)/4; + + // this one is responsible for making fat big ugly easy-to-hit pointer targets + bool is_big_relative_alpha_increase = alpha_diff > (1<<15)/64 && alpha_diff > alpha_old/2; + + if (is_perceptual_alpha_increase || is_big_relative_alpha_increase || is_perceptual_color_change) { + res_p[0] = 1; + } else { + res_p[0] = 0; + } + + a_p += 4; + b_p += 4; + res_p += 1; + } + } +} + diff --git a/lib/strokemap.py b/lib/strokemap.py index 2f111fd..dde5369 100644 --- a/lib/strokemap.py +++ b/lib/strokemap.py @@ -9,6 +9,7 @@ import time, struct import zlib from numpy import * +import mypaintlib import tiledsurface, idletask N = tiledsurface.N @@ -42,22 +43,8 @@ class StrokeShape: a_data = a.get((tx, ty), tiledsurface.transparent_tile).rgba b_data = b.get((tx, ty), tiledsurface.transparent_tile).rgba - # calculate the "perceptual" amount of difference - absdiff = zeros((N, N), 'uint32') - for i in range(4): # RGBA - absdiff += abs(a_data[:,:,i].astype('int32') - b_data[:,:,i]) - # ignore badly visible (parts of) strokes, eg. very faint strokes - # - # This is an arbitrary threshold. If it is too high, an - # ink stroke with slightly different color than the one - # below will not be pickable. If it is too high, barely - # visible strokes will make things below unpickable. - # - threshold = (1<<15)*4 / 16 # require 1/16 of the max difference (also not bad: 1/8) - is_different = absdiff > threshold - # except if there is no previous stroke below it (that is, layer had zero alpha) - is_different |= (absdiff > 0) & (a_data[:,:,3] == 0) - data = is_different.astype('uint8') + data = empty((N, N), 'uint8') + mypaintlib.tile_perceptual_change_strokemap(a_data, b_data, data) data_compressed = zlib.compress(data.tostring()) self.strokemap[tx, ty] = data_compressed