Skip to content

Instantly share code, notes, and snippets.

@hexagit
Created June 22, 2018 05:08
Show Gist options
  • Save hexagit/d507c00c3f97218f3fb747d7f1c52f08 to your computer and use it in GitHub Desktop.
Save hexagit/d507c00c3f97218f3fb747d7f1c52f08 to your computer and use it in GitHub Desktop.
ニアレストネイバー法
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.Assertions;
public partial class Bitmap
{
public uint width { get { return _width; } }
public uint height { get { return _height; } }
public uint count { get { return _width * _height; } }
public Color[] pixels { get { return _pixels; } }
public Color this[int x, int y]
{
get { return _pixels[_width * y + x]; }
set { _pixels[_width * y + x] = value; }
}
public Color this[int index]
{
get { return _pixels[index]; }
set { _pixels[index] = value; }
}
public Bitmap(Texture2D texture)
: this(texture.GetPixels(), (uint)texture.width, (uint)texture.height)
{
}
public Bitmap(uint width, uint height)
: this(new Color[width * height], width, height)
{
}
public Bitmap(Color[] pixels, uint width, uint height)
{
Assert.IsTrue(pixels.Length == width * height);
_width = width;
_height = height;
_pixels = pixels;
}
public Bitmap copy()
{
var bitmap = new Bitmap(_width, _height);
_pixels.CopyTo(bitmap._pixels, 0);
return bitmap;
}
public Texture2D createTexture()
{
var texture = new Texture2D((int)_width, (int)_height, TextureFormat.RGBA32, false);
texture.SetPixels(_pixels);
texture.Apply();
return texture;
}
public Color get(int x, int y)
{
x = clamp(x, 0, (int)_width - 1);
y = clamp(y, 0, (int)_height - 1);
return this[x, y];
}
private Bitmap resizeNearestNeighbor(uint width, uint height)
{
var bitmap = new Bitmap(width, height);
// スケール
var scaleX = (float)width / _width;
var scaleY = (float)height / _height;
// 単位を原画像の座標系に変換
var unitX = 1.0f / scaleX;
var unitY = 1.0f / scaleY;
// 1ピクセル幅を考慮した座標の補正
var correctionX = unitX * 0.5f;
var correctionY = unitY * 0.5f;
parallelFor(0, (int)bitmap._height, y => {
for(int x = 0; x < bitmap._width; ++x) {
// 原画像の座標系に変換
var srcX = unitX * x + correctionX;
var srcY = unitY * y + correctionY;
bitmap[x, y] = get((int)srcX, (int)srcY);
}
});
return bitmap;
}
private static int clamp(int value, int min, int max)
{
if(value > max) return max;
if(value < min) return min;
return value;
}
private static void parallelFor(int start, int end, Action<int> action)
{
var length = Math.Abs(end - start);
if(length == 0) return;
// start <= endを保証する
if(start > end) {
var tmp = start;
start = end;
end = tmp;
}
extendHandlePoolCapacity(length);
// 並列タスクの生成と同期オブジェクトの取得
var index = 0;
var handles = new ManualResetEvent[length];
for(int i = start; i < end; ++i) {
var arg = i;
var handle = popHandle();
ThreadPool.QueueUserWorkItem(state => {
action(arg);
handle.Set();
});
handles[index++] = handle;
}
// 並列タスクの終了待ち
foreach(var handle in handles) {
handle.WaitOne();
pushHandle(handle);
}
}
private static void extendHandlePoolCapacity(int capacity)
{
if(_handlePool.Capacity < capacity) {
_handlePool.Capacity = capacity;
}
}
private static void pushHandle(ManualResetEvent handle)
{
_handlePool.Add(handle);
}
private static ManualResetEvent popHandle()
{
if(_handlePool.Count <= 0) {
return new ManualResetEvent(false);
}
var lastIndex = _handlePool.Count - 1;
var handle = _handlePool[lastIndex];
_handlePool.RemoveAt(lastIndex);
handle.Reset();
return handle;
}
private static readonly List<ManualResetEvent> _handlePool = new List<ManualResetEvent>();
private uint _width = 0u;
private uint _height = 0u;
private Color[] _pixels = null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment