Nope, don't need XYZ
This commit is contained in:
parent
8b500b16cb
commit
e979df03bc
19
convert.py
19
convert.py
|
@ -91,18 +91,15 @@ def main():
|
|||
if args.show_input:
|
||||
image_py.resize(image, screen.NATIVE_X_RES, screen.NATIVE_Y_RES * 2,
|
||||
srgb_output=True).show()
|
||||
resized = np.array(image_py.resize(image, screen.X_RES,
|
||||
screen.Y_RES,
|
||||
gamma=args.gamma_correct)).astype(
|
||||
rgb = np.array(image_py.resize(image, screen.X_RES,
|
||||
screen.Y_RES,
|
||||
gamma=args.gamma_correct) / 255).astype(
|
||||
np.float32)
|
||||
|
||||
# convert from sRGB1-linear to CAM02UCS perceptually uniform colour space
|
||||
xyz = colour.convert(
|
||||
resized / 255, "RGB", "CIE XYZ").astype(np.float32)
|
||||
|
||||
# bits24 = np.arange(2**24).reshape(-1,1)
|
||||
# all_rgb = (np.concatenate( [bits24 >> 16 & 0xff, bits24 >> 8 & 0xff, bits24 & 0xff], axis=1) / 255).astype(np.float32)
|
||||
# all_xyz = colour.convert(all_rgb, "RGB", "CIE XYZ")
|
||||
# bits24 = np.arange(2 ** 24).reshape(-1, 1)
|
||||
# all_rgb = (np.concatenate(
|
||||
# [bits24 >> 16 & 0xff, bits24 >> 8 & 0xff, bits24 & 0xff],
|
||||
# axis=1) / 255).astype(np.float32)
|
||||
# all_cam16 = colour.convert(all_rgb, "RGB", "CAM16UCS").astype(np.float32)
|
||||
# f = np.memmap("rgb_to_cam16ucs.data", mode="w+", dtype=np.float32,
|
||||
# shape=all_cam16.shape)
|
||||
|
@ -114,7 +111,7 @@ def main():
|
|||
shape=(2 ** 24, 3))
|
||||
dither = dither_pattern.PATTERNS[args.dither]()
|
||||
output_nbit, _ = dither_pyx.dither_image(
|
||||
screen, xyz, dither, lookahead, args.verbose, all_cam16)
|
||||
screen, rgb, dither, lookahead, args.verbose, all_cam16)
|
||||
bitmap = screen.pack(output_nbit)
|
||||
|
||||
# Show output image by rendering in target palette
|
||||
|
|
27
dither.pyx
27
dither.pyx
|
@ -87,7 +87,7 @@ cdef inline unsigned char lookahead_pixels(unsigned char last_pixel_nbit, unsign
|
|||
#
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
cdef int dither_lookahead(Dither* dither, float[:, :, ::1] palette_cam16, float[:, :, ::1] palette_xyz,
|
||||
cdef int dither_lookahead(Dither* dither, float[:, :, ::1] palette_cam16, float[:, :, ::1] palette_rgb,
|
||||
float[:, :, ::1] image_rgb, int x, int y, int lookahead, unsigned char last_pixels,
|
||||
int x_res, float[:,::1] all_cam16ucs) nogil:
|
||||
cdef int i, j, k
|
||||
|
@ -102,6 +102,7 @@ cdef int dither_lookahead(Dither* dither, float[:, :, ::1] palette_cam16, float[
|
|||
cdef int xxr = min(x + lookahead, x_res)
|
||||
cdef int lah_shape1 = xxr - x
|
||||
cdef int lah_shape2 = 3
|
||||
# XXX use a memoryview
|
||||
cdef float *lah_image_rgb = <float *> malloc(lah_shape1 * lah_shape2 * sizeof(float))
|
||||
cdef float[::1] lah_cam16ucs
|
||||
|
||||
|
@ -130,10 +131,11 @@ cdef int dither_lookahead(Dither* dither, float[:, :, ::1] palette_cam16, float[
|
|||
# options_rgb choices are fixed, but we can still distribute quantization error
|
||||
# from having made these choices, in order to compute the total error.
|
||||
for k in range(3):
|
||||
quant_error[k] = lah_image_rgb[j * lah_shape2 + k] - palette_xyz[next_pixels, phase, k]
|
||||
quant_error[k] = lah_image_rgb[j * lah_shape2 + k] - palette_rgb[next_pixels, phase, k]
|
||||
apply_one_line(dither, xl, xr, j, lah_image_rgb, lah_shape2, quant_error)
|
||||
|
||||
lah_cam16ucs = xyz_to_cam16ucs(all_cam16ucs, lah_image_rgb[j*lah_shape2], lah_image_rgb[j*lah_shape2+1], lah_image_rgb[j*lah_shape2+2])
|
||||
lah_cam16ucs = rgb_to_cam16ucs(
|
||||
all_cam16ucs, lah_image_rgb[j*lah_shape2], lah_image_rgb[j*lah_shape2+1], lah_image_rgb[j*lah_shape2+2])
|
||||
total_error += colour_distance_squared(lah_cam16ucs, palette_cam16[next_pixels, phase])
|
||||
|
||||
if total_error >= best_error:
|
||||
|
@ -147,12 +149,13 @@ cdef int dither_lookahead(Dither* dither, float[:, :, ::1] palette_cam16, float[
|
|||
return best
|
||||
|
||||
|
||||
cdef inline float[::1] xyz_to_cam16ucs(float[:, ::1] all_cam16ucs, float x, float y, float z) nogil:
|
||||
cdef int flat_xyz = (<int>(x*255) << 16) + (<int>(y*255) << 8) + <int>(z*255)
|
||||
return all_cam16ucs[flat_xyz]
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
cdef inline float[::1] rgb_to_cam16ucs(float[:, ::1] all_cam16ucs, float r, float g, float b) nogil:
|
||||
cdef int rgb_24bit = (<int>(r*255) << 16) + (<int>(g*255) << 8) + <int>(b*255)
|
||||
return all_cam16ucs[rgb_24bit]
|
||||
|
||||
|
||||
# XXX fix signature
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
cdef inline float colour_distance_squared(float[::1] colour1, float[::1] colour2) nogil:
|
||||
|
@ -279,10 +282,10 @@ def dither_image(screen, float[:, :, ::1] image_rgb, dither, int lookahead, unsi
|
|||
for k in range(3):
|
||||
palette_cam16[i, j, k] = screen.palette.CAM16UCS[i, j][k]
|
||||
|
||||
cdef float[:, :, ::1] palette_xyz = np.zeros((len(screen.palette.XYZ), 4, 3), dtype=np.float32)
|
||||
for i, j in screen.palette.XYZ.keys():
|
||||
cdef float[:, :, ::1] palette_rgb = np.zeros((len(screen.palette.RGB), 4, 3), dtype=np.float32)
|
||||
for i, j in screen.palette.RGB.keys():
|
||||
for k in range(3):
|
||||
palette_xyz[i, j, k] = screen.palette.XYZ[i, j][k]
|
||||
palette_rgb[i, j, k] = screen.palette.RGB[i, j][k] / 255
|
||||
|
||||
cdef Dither cdither
|
||||
cdither.y_shape = dither.PATTERN.shape[0]
|
||||
|
@ -311,7 +314,7 @@ def dither_image(screen, float[:, :, ::1] image_rgb, dither, int lookahead, unsi
|
|||
# Apply error diffusion for each of these 2**N choices, and compute which produces the closest match
|
||||
# to the source image over the succeeding N pixels
|
||||
best_next_pixels = dither_lookahead(
|
||||
&cdither, palette_cam16, palette_xyz, image_rgb, x, y, lookahead, output_pixel_nbit, xres, all_cam16ucs)
|
||||
&cdither, palette_cam16, palette_rgb, image_rgb, x, y, lookahead, output_pixel_nbit, xres, all_cam16ucs)
|
||||
# Apply best choice for next 1 pixel
|
||||
output_pixel_nbit = lookahead_pixels(output_pixel_nbit, best_next_pixels, lookahead=0)
|
||||
#else:
|
||||
|
@ -321,7 +324,7 @@ def dither_image(screen, float[:, :, ::1] image_rgb, dither, int lookahead, unsi
|
|||
|
||||
# Apply error diffusion from chosen output pixel value
|
||||
for i in range(3):
|
||||
output_pixel_rgb[i] = palette_xyz[output_pixel_nbit, x % 4, i]
|
||||
output_pixel_rgb[i] = palette_rgb[output_pixel_nbit, x % 4, i]
|
||||
quant_error[i] = image_rgb[y,x,i] - output_pixel_rgb[i]
|
||||
apply(&cdither, xres, yres, x, y, image_rgb, quant_error)
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@ class Palette:
|
|||
for k, v in self.SRGB.items():
|
||||
self.RGB[k] = (np.clip(image.srgb_to_linear_array(v / 255), 0.0,
|
||||
1.0) * 255).astype(np.uint8)
|
||||
self.CAM16UCS[k] = colour.convert(v / 255, "sRGB",
|
||||
"CAM16UCS").astype(np.float32)
|
||||
self.XYZ[k] = colour.convert(v / 255, "sRGB",
|
||||
"CIE XYZ").astype(np.float32)
|
||||
self.CAM16UCS[k] = colour.convert(
|
||||
v / 255, "sRGB", "CAM16UCS").astype(np.float32)
|
||||
# self.XYZ[k] = colour.convert(v / 255, "sRGB",
|
||||
# "CIE XYZ").astype(np.float32)
|
||||
|
||||
# print(self.CAM02UCS)
|
||||
|
||||
|
|
Loading…
Reference in New Issue