저는 Golang에서 이미지의 크기를 조정하는 몇 가지 기본 방법을 쓰고 있습니다. 이미지 크기 조정에 대한 여러 게시물을 보았습니다. 그러나 내 인생에서 내가 무엇을 놓치고 있는지 알 수는 없습니다 ...Golang에서 Lanczos Resampling을 사용하여 거친 가장자리를 만들었습니다.
기본적으로 내 문제는 Golang에서 이미지 크기를 조정할 때 내 결과가 나타나는 것입니다. 앨리어싱이 많이 필요합니다.
이미지를 반복적으로 다운 샘플링하려고 시도했지만 개선되지 않았습니다.
func resize(original image.Image,
edgeSize int, filterSize int) image.Image {
oldBounds := original.Bounds()
if oldBounds.Dx() < edgeSize && oldBounds.Dy() < edgeSize {
// No resize necessary
return original
}
threshold := edgeSize * 4/3
if oldBounds.Dx() > threshold || oldBounds.Dy() > threshold {
fmt.Println("Upstream")
original = customResizeImageToFitBounds(original, threshold, filterSize)
oldBounds = original.Bounds()
}
newBounds := getNewBounds(oldBounds, edgeSize)
resized := image.NewRGBA(newBounds)
var ratioX = float64(oldBounds.Dx())/float64(newBounds.Dx())
var ratioY = float64(oldBounds.Dy())/float64(newBounds.Dy())
for x := 0; x < newBounds.Dx(); x++ {
for y := 0; y < newBounds.Dy(); y++ {
sourceX := ratioX * float64(x)
minX := int(math.Floor(sourceX))
sourceY := ratioY * float64(y)
minY := int(math.Floor(sourceY))
sampleSize := filterSize<<1 + 1
var xCoeffs = make([]float64, sampleSize)
var yCoeffs = make([]float64, sampleSize)
var sumX = 0.0
var sumY = 0.0
for i := 0; i < sampleSize; i++ {
xCoeffs[i] = lanczos(filterSize, sourceX-float64(minX+i-filterSize))
yCoeffs[i] = lanczos(filterSize, sourceY-float64(minY+i-filterSize))
sumX += xCoeffs[i]
sumY += yCoeffs[i]
}
for i := 0; i < sampleSize; i++ {
xCoeffs[i] /= sumX
yCoeffs[i] /= sumY
}
rgba := make([]float64, 4)
for i := 0; i < sampleSize; i++ {
if yCoeffs[i] == 0.0 {
continue
}
currY := minY + i - filterSize
rgbaRow := make([]float64, 4)
for j := 0; j < sampleSize; j++ {
if xCoeffs[j] == 0.0 {
continue
}
currX := minX + i - filterSize
rij, gij, bij, aij := original.At(
clamp(currX, currY, oldBounds)).RGBA()
rgbaRow[0] += float64(rij) * xCoeffs[j]
rgbaRow[1] += float64(gij) * xCoeffs[j]
rgbaRow[2] += float64(bij) * xCoeffs[j]
rgbaRow[3] += float64(aij) * xCoeffs[j]
}
rgba[0] += float64(rgbaRow[0]) * yCoeffs[i]
rgba[1] += float64(rgbaRow[1]) * yCoeffs[i]
rgba[2] += float64(rgbaRow[2]) * yCoeffs[i]
rgba[3] += float64(rgbaRow[3]) * yCoeffs[i]
}
rgba[0] = clampRangeFloat(0, rgba[0], 0xFFFF)
rgba[1] = clampRangeFloat(0, rgba[1], 0xFFFF)
rgba[2] = clampRangeFloat(0, rgba[2], 0xFFFF)
rgba[3] = clampRangeFloat(0, rgba[3], 0xFFFF)
var rgbaF [4]uint64
rgbaF[0] = (uint64(math.Floor(rgba[0]+0.5)) * 0xFF)/0xFFFF
rgbaF[1] = (uint64(math.Floor(rgba[1]+0.5)) * 0xFF)/0xFFFF
rgbaF[2] = (uint64(math.Floor(rgba[2]+0.5)) * 0xFF)/0xFFFF
rgbaF[3] = (uint64(math.Floor(rgba[3]+0.5)) * 0xFF)/0xFFFF
rf := uint8(clampRangeUint(0, uint32(rgbaF[0]), 255))
gf := uint8(clampRangeUint(0, uint32(rgbaF[1]), 255))
bf := uint8(clampRangeUint(0, uint32(rgbaF[2]), 255))
af := uint8(clampRangeUint(0, uint32(rgbaF[3]), 255))
resized.Set(x, y, color.RGBA{R: rf, G: gf, B: bf, A: af})
}
}
return resized
}
// Machine epsilon
var epsilon = math.Nextafter(1.0, 2.0) - 1
func lanczos(filterSize int, x float64) float64 {
x = math.Abs(x)
fs := float64(filterSize)
if x < epsilon {
return 1.0
}
if x > fs {
return 0
}
piX := math.Pi * x
piXOverFS := piX/fs
return (math.Sin(piX)/piX) * (math.Sin(piXOverFS)/(piXOverFS))
}
내가 최적화 살펴보기 전에 좋은 품질의 결과를 얻을 원하기 때문에 그것은, 특히 확대됨되지 않습니다 :
여기 내 코드입니다.
이미지 리샘플링 경험이있는 사람이라면 문제가 될 수있는 것이 있습니까? 다음
내 결과입니다 : 참고로
, 여기에 내 소스 이미지 Ruby를 통해 RMagick/ImageMagick을 사용하여 얻은 결과 (내가 뭘 촬영했는지) :아무도 원활하게 다운 스케일 결과를 얻을 수있는 방법에 대한 조언이 있습니까? 이 특별한 예는 매우 격렬한 다운 스케일이지만, Rmagick은 훌륭한 품질로 매우 빠르게 축소 할 수 있었으므로 가능해야합니다.
나는 Lanczos3 Resampling이 좋은 결과를 산출한다고 말했고, 그게 내가 여기서 사용하려고하는 것입니다. 제 구현이 맞는지 확실하지 않습니다.
또한 참고로, golang의 "At"함수는 [0, 0xFFFF] ([0, 65535]) 범위의 rgba 값을 반환하기 때문에 0xFF/0xFFFF 변환이 사용되지만 "Set"은 [0, 0xFF] ([0, 255]) 범위로 초기화 됨
지금은 성능보다 품질에 더 관심이 있습니다.