Last active
August 9, 2022 20:26
-
-
Save unitycoder/7649f62a6eceeb761db7f0092d9c3df1 to your computer and use it in GitHub Desktop.
FAST Algorithm for Corner Detection (Unity)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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