Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save romancone/936b10f9f0541c526f4f16b1dfd6da86 to your computer and use it in GitHub Desktop.

Select an option

Save romancone/936b10f9f0541c526f4f16b1dfd6da86 to your computer and use it in GitHub Desktop.
 Smart resize for backend
package main
import (
"errors"
"image"
"math"
// Используем стандартный пакет для качественного и быстрого ресайза
"golang.org/x/image/draw"
)
const PatchSize = 16
// ResizeOptions содержит параметры для оптимизации изображения
type ResizeOptions struct {
TokenBudget int // Например: 70, 140, 280, 560, 1120
}
// SmartResizeVision принимает исходное изображение и подгоняет его под бюджет токенов Gemma 4,
// строго сохраняя пропорции кадра и кратность сторон 16 пикселям.
func SmartResizeVision(img image.Image, opts ResizeOptions) (image.Image, error) {
if opts.TokenBudget <= 0 {
return nil, errors.New("token budget must be greater than 0")
}
bounds := img.Bounds()
origW := bounds.Dx()
origH := bounds.Dy()
if origW == 0 || origH == 0 {
return nil, errors.New("invalid image dimensions")
}
// 1. Вычисляем оптимальную сетку патчей (gridW и gridH)
targetW, targetH := calculateOptimalDimensions(origW, origH, opts.TokenBudget)
// 2. Если изображение уже совпадает с целевым размером, возвращаем его
if origW == targetW && origH == targetH {
return img, nil
}
// 3. Выполняем ресайз с использованием высококачественного интерполятора BiLinear
// (BiLinear — оптимальный баланс скорости и качества деталей для нейросетей)
rect := image.Rect(0, 0, targetW, targetH)
dst := image.NewRGBA(rect)
draw.BiLinear.Scale(dst, rect, img, bounds, draw.Over, nil)
return dst, nil
}
// calculateOptimalDimensions подбирает размеры сторон кратными PatchSize,
// минимизируя искажение Aspect Ratio и не превышая TokenBudget.
func calculateOptimalDimensions(origW, grandchildrenH int, budget int) (int, int) {
origRatio := float64(origW) / float64(grandchildrenH)
bestGridW := 1
bestGridH := 1
minRatioDiff := math.MaxFloat64
maxTokensUsed := 0
// Ограничиваем область поиска физическим пределом по сетке
maxDim := int(math.Ceil(math.Sqrt(float64(budget)))) * 2
for gridW := 1; gridW <= maxDim; gridW++ {
for gridH := 1; gridH <= maxDim; gridH++ {
tokens := gridW * gridH
// Нас интересуют только комбинации, проходящие в лимит токенов
if tokens <= budget {
currentRatio := float64(gridW) / float64(gridH)
ratioDiff := math.Abs(currentRatio - origRatio)
// Шаг 1: Ищем минимальное искажение пропорций
// Шаг 2: При одинаковом качестве пропорций максимизируем утилизацию токенов (детализацию)
if ratioDiff < minRatioDiff || (math.Abs(ratioDiff-minRatioDiff) < 1e-4 && tokens > maxTokensUsed) {
minRatioDiff = ratioDiff
bestGridW = gridW
bestGridH = gridH
maxTokensUsed = tokens
}
}
}
}
// Переводим сетку патчей обратно в пиксели
return bestGridW * PatchSize, bestGridH * PatchSize
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment