ImageMagick 按不同指标进行颜色映射?

问题描述 投票:0回答:1

我想使用 ImageMagick 将图片转换为4位RGBI格式。事实证明,我可以通过将调色板作为单独的步骤来做到这一点。然而结果却很不理想。

例如,这是上述 15 色调色板的输入图像:

这是 RGBI4 调色板的输出:

相比之下,仅使用 8 种颜色和

-posterize 2
,即不允许中等强度,我得到的图片实际上更好:

请注意,第二次转换中使用的所有颜色也可用于第一次转换;它们只是没有被 ImageMagick 选择。

对我来说,这表明问题在于 ImageMagick 用于选择颜色的颜色空间度量。我如何控制它以获得至少与

-posterize 2
一样好的东西?

imagemagick color-space color-conversion
1个回答
0
投票

AFAIK,ImageMagick always 在 RGB 颜色空间中进行重新映射,这不会为您产生很好的结果。因此,我尝试转换为不同的色彩空间,但将其从ImageMagick隐藏,因此它认为图像和调色板是RGB,然后,当重新映射完成时,我承认数据是HSV并转换回RGB。对于您的示例图像来说,它似乎工作正常:

#!/bin/bash

# Make RGBI palette and save in HSV colourspace as three separate PGM images (no colourspace specified so IM treats as RGB)
magick $(for l in 128 255                        
  do
    for r in 0 $l
    do
      for g in 0 $l
      do
        for b in 0 $l
        do
          echo "xc:rgb($r,$g,$b)"
        done
      done
    done
  done) +append -unique-colors -colorspace HSV -separate pal-%d.pgm

# Split input image into HSV too and hide colourspace using PGM
magick input.png -colorspace HSV -separate chan-%d.pgm

# Recombine image and palette (pretending RGB), remap, admit HSV colourspace
magick chan-[012].pgm -combine \
   \( pal-[012].pgm -combine -write MPR:palette +delete \) \
   +dither -remap mpr:palette -set colorspace HSV result.png

我们可能必须处理黄色...事实上,这让我想到了另一个想法...我们可以分别采用输入图像中的几种单独颜色,并强制每个颜色都为新的输出颜色,one-at-一次...

是的,这就是解决方案,我可以在输入图像中选择单独的颜色(在任何容差范围内,或“模糊”)并将其更改为我想要的任何颜色。所以在这里,我会让黄色变成红色,绿色变成洋红色:

magick input.png -fuzz 10% \
   -fill red     -opaque "rgb(201,215,112)" \
   -fill magenta -opaque "rgb(95,159,67)" result.png

我将让您对输入颜色进行精确映射...


仅供参考,这是我在 Python 和 OpenCV 中编写的丑陋的概念验证代码 - 顺便说一句,它可以工作:

#!/usr/bin/env python3

import numpy as np
import cv2 as cv
from functools import lru_cache 

def show(name, na):
   print(f'{name}: {na.shape}, {na.dtype}, {na.min()}, {na.max()}')

# Load image and convert to Luv
im    = cv.imread('input.png')
imLab = cv.cvtColor(np.float32(im/255.), cv.COLOR_BGR2Luv)
rows, cols, ch = im.shape
show('imLab', imLab)

# Load palette and convert to Luv
pal  = cv.imread('palette.png')
pLab = cv.cvtColor(np.float32(pal/255.), cv.COLOR_BGR2Luv)
pEntries = 15
show('pLab', pLab)

def labnearest(i0,i1,i2):
   dNearest = 1_000_000
   for pEntry in range(pEntries):
      p0, p1, p2 = pLab[0,pEntry,0], pLab[0,pEntry,1], pLab[0,pEntry,2]
      # Work out distance between this pixel and this palette entry
      d = (p0 - i0)*(p0 - i0) + (p1 - i1)*(p1 -i1) + (p2 - i2)*(p2 - i2)
      if d < dNearest:
         dNearest = d
         result = (p0, p1, p2)
   return result

for x in range(rows):
   for y in range(cols):
       px = imLab[x,y]
       imLab[x,y] = labnearest(px[0], px[1], px[2])

show('imLab', imLab)
res = (cv.cvtColor(imLab, cv.COLOR_Luv2BGR)*255).astype(np.uint8)
show('res', res)
cv.imwrite('result.png', res)
© www.soinside.com 2019 - 2024. All rights reserved.