通过 python 算法将 Square Hald clut 转换为 Classic Hald clut
Convert Square Hald clut to Classic Hald clut through a python alghoritm
我的问题是:我有一个 Square Hald 8 512x512px,我想把它转换成 .CUBE 文件
- 将 Square Hald 转换为 Classic Hald,然后轻松转换为 CUBE(参见第二个算法)
图片:Square Hald 8 - Classic Hald 8
我正在尝试反转这个简单的 python 算法,该算法可以很好地转换 Classic Hald -> Square Hald:
import numpy, cv2
hald = cv2.imread("classic_hald_8.png")
size = int(hald.shape[0] ** (1.0/3.0) + .5)
clut = numpy.concatenate([
numpy.concatenate(hald.reshape((size,size,size**2,size**2, 3))[row], axis=1)
for row in range(size)
])
cv2.imwrite("square_hald_8.png", clut)
import imageio as iio, numpy as np
imagen=iio.imread("Classic_Hald_8.png")
r,g,b=(imagen[:,:,0]).reshape(-1), (imagen[:,:,1]).reshape(-1), (imagen[:,:,2]).reshape(-1)
np.savetxt("Classic_Hald_8.cube",X=np.column_stack((r/255,g/255,b/255)),fmt='%1.6f', header="LUT_3D_SIZE 64", comments="")
我们需要重塑价值观。一些想法或建议?谢谢
UPDATE2: 感谢 GrossGrade 作者 Eugene Vdovin,我已经解决了。如果有人建议实施 3D 结构(也许使用 numpy?),则可以很好地接受。我对 python
很菜鸟
from PIL import Image
im = Image.open('test.png','r')
values = im.load()
hald_side_in_pixels = im.size[0]
hald_in_pixels = im.size[0]*im.size[0]
lutSize = int(hald_in_pixels ** (1.0/3.0) + .5)
fr = [0.0]*hald_in_pixels
fg = [0.0]*hald_in_pixels
fb = [0.0]*hald_in_pixels
cubeIndex = 0
for y in range(hald_side_in_pixels):
for x in range(hald_side_in_pixels):
iR = cubeIndex % lutSize
iG = y % lutSize
iB = int(x/lutSize)+(int(y/lutSize)*int(hald_side_in_pixels/lutSize))
idx = iR * lutSize * lutSize + iG * lutSize + iB
fr[idx],fg[idx],fb[idx] = values[x,y]
cubeIndex+=1
with open("test.cube", "w") as output:
output.write("DOMAIN_MIN 0 0 0\nDOMAIN_MAX 1 1 1\nLUT_3D_SIZE " + str(lutSize) + '\n')
for iB in range(lutSize):
for iG in range(lutSize):
for iR in range(lutSize):
idx = iR * lutSize * lutSize + iG * lutSize + iB
output.write((str("%.9f" % (fr[idx]/255)) + ' ' + str("%.9f" % (fg[idx]/255)) + ' ' + str("%.9f" % (fb[idx]/255)))+ '\n')
output.close()
UPDATE3: 我听从了建议,我用 numpy 创建了一个 3D 数组,现在更干净了,但它比 3x 1D 数组慢了大约 150ms,我post代码
from PIL import Image
import numpy as np
im = Image.open('test.png','r')
values = im.load()
hald_side_in_pixels = im.size[0]
lutSize = int((hald_side_in_pixels*hald_side_in_pixels) ** (1.0/3.0) + .5)
LUT = np.empty((lutSize,lutSize,lutSize), dtype=bytearray)
cubeIndex = 0
for y in range(hald_side_in_pixels):
for x in range(hald_side_in_pixels):
iR = cubeIndex % lutSize
iG = y % lutSize
iB = int(x/lutSize)+(int(y/lutSize)*int(hald_side_in_pixels/lutSize))
LUT[iR,iG,iB]=values[x,y]
cubeIndex+=1
with open("test1.cube", "w") as output:
output.write("DOMAIN_MIN 0 0 0\nDOMAIN_MAX 1 1 1\nLUT_3D_SIZE " + str(lutSize) + '\n')
for iB in range(lutSize):
for iG in range(lutSize):
for iR in range(lutSize):
output.write((str("%.9f" % (LUT[iR,iG,iB][0]/255)) + ' ' + str("%.9f" % (LUT[iR,iG,iB][1]/255)) + ' ' + str("%.9f" % (LUT[iR,iG,iB][2]/255)))+ '\n')
output.close()
这里是解析HALD图像的每个像素并将其值放入3DLUT的C++代码,随后以CUBE格式保存到文件中。代码缺少一些东西来保持一切紧凑。希望这会帮助您理解索引算法,以便您可以自己在 python 中实现它。
std::string formatstring(const char *Format, ...)
{
if(Format == NULL || Format[0] == '[=10=]') return "";
static std::string Res;
va_list args;
va_start(args, Format);
int len = _vscprintf(Format, args);
Res.resize(len);
vsprintf((char*)Res.data(), Format, args);
va_end(args);
return Res;
}
void convert_hald_to_cube()
{
CLUT LUT; // you must implement a class to store 3DLUT data of any size
// Here you getting your HALD image data into a 2D-array hald_colors
// ...
// Getting 3DLUT values from a HALD 2D-array
int hald_side_in_pixels = 512;
int lutSize = (int)(powf((float)hald_side_in_pixels*hald_side_in_pixels,1.f/3.f)+0.5f); // +0.5f is for rounding a positive value
int iR,iG,iB;
int cubeIndex = 0;
for(int y=0; y<hald_side_in_pixels; ++y)
{
for(int x=0; x<hald_side_in_pixels; ++x)
{
iR = cubeIndex % lutSize;
iG = y % lutSize;
iB = (x/lutSize)+((y/lutSize)*(hald_side_in_pixels/lutSize));
// Here you copy the hald_colors[x][y] color value to the 3DLUT voxel value at indexes {iR,iG,iB}
cubeIndex++;
}
}
// Putting 3DLUT values to a CUBE file
FILE *f = fopen("OutputCubeFile.cube", "w+");
fputs("TITLE my cube file\n",f);
fputs("DOMAIN_MIN 0 0 0\n",f);
fputs("DOMAIN_MAX 1 1 1\n",f);
std::string s = "LUT_3D_SIZE " + std::to_string((_ULonglong)lutSize) + "\n";
fputs(s.c_str(),f);
for(int iB=0; iB<lutSize; ++iB)
{
for(int iG=0; iG<lutSize; ++iG)
{
for(int iR=0; iR<lutSize; ++iR)
{
float fr,fg,fb;
// Here you copy the 3DLUT voxel value at indexes {iR,iG,iB} to the values fr,fg,fb
std::string outputvalues = formatstring("%.9f %.9f %.9f\n",fr,fg,fb);
fputs(outputvalues.c_str(),f);
}
}
}
fclose(f);
}
我的问题是:我有一个 Square Hald 8 512x512px,我想把它转换成 .CUBE 文件
- 将 Square Hald 转换为 Classic Hald,然后轻松转换为 CUBE(参见第二个算法) 图片:Square Hald 8 - Classic Hald 8
我正在尝试反转这个简单的 python 算法,该算法可以很好地转换 Classic Hald -> Square Hald:
import numpy, cv2 hald = cv2.imread("classic_hald_8.png") size = int(hald.shape[0] ** (1.0/3.0) + .5) clut = numpy.concatenate([ numpy.concatenate(hald.reshape((size,size,size**2,size**2, 3))[row], axis=1) for row in range(size) ]) cv2.imwrite("square_hald_8.png", clut)
import imageio as iio, numpy as np imagen=iio.imread("Classic_Hald_8.png") r,g,b=(imagen[:,:,0]).reshape(-1), (imagen[:,:,1]).reshape(-1), (imagen[:,:,2]).reshape(-1) np.savetxt("Classic_Hald_8.cube",X=np.column_stack((r/255,g/255,b/255)),fmt='%1.6f', header="LUT_3D_SIZE 64", comments="")
我们需要重塑价值观。一些想法或建议?谢谢
UPDATE2: 感谢 GrossGrade 作者 Eugene Vdovin,我已经解决了。如果有人建议实施 3D 结构(也许使用 numpy?),则可以很好地接受。我对 python
很菜鸟from PIL import Image
im = Image.open('test.png','r')
values = im.load()
hald_side_in_pixels = im.size[0]
hald_in_pixels = im.size[0]*im.size[0]
lutSize = int(hald_in_pixels ** (1.0/3.0) + .5)
fr = [0.0]*hald_in_pixels
fg = [0.0]*hald_in_pixels
fb = [0.0]*hald_in_pixels
cubeIndex = 0
for y in range(hald_side_in_pixels):
for x in range(hald_side_in_pixels):
iR = cubeIndex % lutSize
iG = y % lutSize
iB = int(x/lutSize)+(int(y/lutSize)*int(hald_side_in_pixels/lutSize))
idx = iR * lutSize * lutSize + iG * lutSize + iB
fr[idx],fg[idx],fb[idx] = values[x,y]
cubeIndex+=1
with open("test.cube", "w") as output:
output.write("DOMAIN_MIN 0 0 0\nDOMAIN_MAX 1 1 1\nLUT_3D_SIZE " + str(lutSize) + '\n')
for iB in range(lutSize):
for iG in range(lutSize):
for iR in range(lutSize):
idx = iR * lutSize * lutSize + iG * lutSize + iB
output.write((str("%.9f" % (fr[idx]/255)) + ' ' + str("%.9f" % (fg[idx]/255)) + ' ' + str("%.9f" % (fb[idx]/255)))+ '\n')
output.close()
UPDATE3: 我听从了建议,我用 numpy 创建了一个 3D 数组,现在更干净了,但它比 3x 1D 数组慢了大约 150ms,我post代码
from PIL import Image
import numpy as np
im = Image.open('test.png','r')
values = im.load()
hald_side_in_pixels = im.size[0]
lutSize = int((hald_side_in_pixels*hald_side_in_pixels) ** (1.0/3.0) + .5)
LUT = np.empty((lutSize,lutSize,lutSize), dtype=bytearray)
cubeIndex = 0
for y in range(hald_side_in_pixels):
for x in range(hald_side_in_pixels):
iR = cubeIndex % lutSize
iG = y % lutSize
iB = int(x/lutSize)+(int(y/lutSize)*int(hald_side_in_pixels/lutSize))
LUT[iR,iG,iB]=values[x,y]
cubeIndex+=1
with open("test1.cube", "w") as output:
output.write("DOMAIN_MIN 0 0 0\nDOMAIN_MAX 1 1 1\nLUT_3D_SIZE " + str(lutSize) + '\n')
for iB in range(lutSize):
for iG in range(lutSize):
for iR in range(lutSize):
output.write((str("%.9f" % (LUT[iR,iG,iB][0]/255)) + ' ' + str("%.9f" % (LUT[iR,iG,iB][1]/255)) + ' ' + str("%.9f" % (LUT[iR,iG,iB][2]/255)))+ '\n')
output.close()
这里是解析HALD图像的每个像素并将其值放入3DLUT的C++代码,随后以CUBE格式保存到文件中。代码缺少一些东西来保持一切紧凑。希望这会帮助您理解索引算法,以便您可以自己在 python 中实现它。
std::string formatstring(const char *Format, ...)
{
if(Format == NULL || Format[0] == '[=10=]') return "";
static std::string Res;
va_list args;
va_start(args, Format);
int len = _vscprintf(Format, args);
Res.resize(len);
vsprintf((char*)Res.data(), Format, args);
va_end(args);
return Res;
}
void convert_hald_to_cube()
{
CLUT LUT; // you must implement a class to store 3DLUT data of any size
// Here you getting your HALD image data into a 2D-array hald_colors
// ...
// Getting 3DLUT values from a HALD 2D-array
int hald_side_in_pixels = 512;
int lutSize = (int)(powf((float)hald_side_in_pixels*hald_side_in_pixels,1.f/3.f)+0.5f); // +0.5f is for rounding a positive value
int iR,iG,iB;
int cubeIndex = 0;
for(int y=0; y<hald_side_in_pixels; ++y)
{
for(int x=0; x<hald_side_in_pixels; ++x)
{
iR = cubeIndex % lutSize;
iG = y % lutSize;
iB = (x/lutSize)+((y/lutSize)*(hald_side_in_pixels/lutSize));
// Here you copy the hald_colors[x][y] color value to the 3DLUT voxel value at indexes {iR,iG,iB}
cubeIndex++;
}
}
// Putting 3DLUT values to a CUBE file
FILE *f = fopen("OutputCubeFile.cube", "w+");
fputs("TITLE my cube file\n",f);
fputs("DOMAIN_MIN 0 0 0\n",f);
fputs("DOMAIN_MAX 1 1 1\n",f);
std::string s = "LUT_3D_SIZE " + std::to_string((_ULonglong)lutSize) + "\n";
fputs(s.c_str(),f);
for(int iB=0; iB<lutSize; ++iB)
{
for(int iG=0; iG<lutSize; ++iG)
{
for(int iR=0; iR<lutSize; ++iR)
{
float fr,fg,fb;
// Here you copy the 3DLUT voxel value at indexes {iR,iG,iB} to the values fr,fg,fb
std::string outputvalues = formatstring("%.9f %.9f %.9f\n",fr,fg,fb);
fputs(outputvalues.c_str(),f);
}
}
}
fclose(f);
}