Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Last active August 9, 2022 20:26
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save unitycoder/7649f62a6eceeb761db7f0092d9c3df1 to your computer and use it in GitHub Desktop.
Save unitycoder/7649f62a6eceeb761db7f0092d9c3df1 to your computer and use it in GitHub Desktop.
FAST Algorithm for Corner Detection (Unity)
// unity version : https://unitycoder.com/blog/2019/05/09/fast-algorithm-for-corner-detection-in-unity/
// NOTE this is not optimized in any way
// original source https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_fast/py_fast.html
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FeaturesAcceleratedSegmentTest : MonoBehaviour
{
// assign UI rawimage here (image should have [x] read write enabled
public RawImage rawImage;
// assign output UI rawimage here (new texture is created by the script and assigned to this ui element)
public RawImage rawImagePoints;
IEnumerator Start()
{
// offsets for circle of pixels around interest point
var offsets = new List<Vector2Int>();
offsets.Add(new Vector2Int(0, 3)); // 1
offsets.Add(new Vector2Int(1, 3)); // 2
offsets.Add(new Vector2Int(2, 2)); // 3
offsets.Add(new Vector2Int(3, 1)); // 4
offsets.Add(new Vector2Int(3, 0)); // 5
offsets.Add(new Vector2Int(3, -1)); // 6
offsets.Add(new Vector2Int(2, -2)); // 7
offsets.Add(new Vector2Int(1, -3)); // 8
offsets.Add(new Vector2Int(0, -3)); // 9
offsets.Add(new Vector2Int(-1, -3)); // 10
offsets.Add(new Vector2Int(-2, -2)); // 11
offsets.Add(new Vector2Int(-3, -1)); // 12
offsets.Add(new Vector2Int(-3, 0)); // 13
offsets.Add(new Vector2Int(-3, 1)); // 14
offsets.Add(new Vector2Int(-2, 2)); // 15
offsets.Add(new Vector2Int(-1, 3)); // 16
// get source texture
var sourcetex = (Texture2D)rawImage.mainTexture;
// create overlay texture
var tex = new Texture2D(sourcetex.width, sourcetex.height, TextureFormat.ARGB32, false, false);
tex.filterMode = FilterMode.Point;
// clear alpha for output
var temp = tex.GetPixels32(0);
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Color.clear;
}
tex.SetPixels32(temp);
tex.Apply(false);
// update preview
rawImagePoints.texture = tex;
// loop all pixels, but not edges
for (int y = 4; y < sourcetex.height - 4; y++)
{
for (int x = 4; x < sourcetex.width - 4; x++)
{
// Select a pixel p in the image which is to be identified as an interest point or not
var px = x;
var py = y;
// Let its intensity be Ip
var c = sourcetex.GetPixel(px, py);
var ip = Brightness(c);
// Select appropriate threshold value t.
var t = 0.1f;
// Consider a circle of 16 pixels around the pixel under test. (This is a Bresenham circle of radius 3.)
// get pixels in circle from source image
var sourcePixels = new Color[offsets.Count];
for (int i = 0; i < sourcePixels.Length; i++)
{
sourcePixels[i] = sourcetex.GetPixel(px + offsets[i].x, py + offsets[i].y);
}
//now the pixel p is a corner if there exists a set of n contiguous pixels in the circle(of 16 pixels) which are all brighter than Ip +t,
// or all darker than Ip - t. (The authors have used n = 12 in the first version of the algorithm)
// check how many connected pixels, with those values
// find brighter continuous count
int brighterCount = 0;
int brighterCountMax = 0;
for (int i = 0; i < sourcePixels.Length * 2; i++)
{
var pc = Brightness(sourcePixels[i % sourcePixels.Length]);
if (pc > ip + t)
{
brighterCount++;
if (brighterCount > brighterCountMax) brighterCountMax = brighterCount;
}
else
{
brighterCount = 0;
}
}
// find darker continuous count
int darkerCount = 0;
int darkerCountMax = 0;
for (int i = 0; i < sourcePixels.Length * 2; i++)
{
var pc = Brightness(sourcePixels[i % sourcePixels.Length]);
if (pc < Mathf.Abs(ip - t))
{
darkerCount++;
if (darkerCount > darkerCountMax) darkerCountMax = darkerCount;
}
else
{
darkerCount = 0;
}
}
// how many continuous matches needed
int n = 12;
bool isEdge = false;
if (brighterCountMax > n) isEdge = true;
if (darkerCountMax > n) isEdge = true;
// draw feature edges to output texture
if (isEdge)
{
tex.SetPixel(px, py, Color.green);
}
} // for x
tex.Apply(false);
yield return null;
} // for y
}
// http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
private float Brightness(Color c)
{
return Mathf.Sqrt(c.r * c.r * .241f + c.g * c.g * .691f + c.b * c.b * .068f);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment