Saya kebetulan mengimplementasikan sesuatu seperti ini pada OpenGL ES 2.0 menggunakan deteksi sudut Harris, dan sementara saya belum sepenuhnya selesai, saya pikir saya akan berbagi implementasi berbasis shader yang saya miliki sejauh ini. Saya telah melakukan ini sebagai bagian dari kerangka kerja open source berbasis iOS , sehingga Anda dapat memeriksa kode jika Anda ingin tahu bagaimana beberapa langkah tertentu bekerja.
Untuk melakukan ini, saya menggunakan langkah-langkah berikut:
- Kurangi gambar ke nilai luminansinya menggunakan produk titik dari nilai RGB dengan vektor (0,2125, 0,7154, 0,0721).
Hitung turunan X dan Y dengan mengurangi nilai saluran merah dari piksel kiri dan kanan dan di atas dan di bawah piksel saat ini. Saya kemudian menyimpan turunan x kuadrat di saluran merah, turunan Y kuadrat di saluran hijau, dan produk turunan X dan Y di saluran biru. Shader fragmen untuk ini terlihat seperti berikut:
precision highp float;
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 bottomTextureCoordinate;
uniform sampler2D inputImageTexture;
void main()
{
float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
float verticalDerivative = abs(-topIntensity + bottomIntensity);
float horizontalDerivative = abs(-leftIntensity + rightIntensity);
gl_FragColor = vec4(horizontalDerivative * horizontalDerivative, verticalDerivative * verticalDerivative, verticalDerivative * horizontalDerivative, 1.0);
}
di mana variasi hanyalah koordinat tekstur offset di setiap arah. Saya menghitung ulang ini dalam vertex shader untuk menghilangkan pembacaan tekstur dependen, yang terkenal lambat pada GPU seluler ini.
Terapkan blur Gaussian ke gambar turunan ini. Saya menggunakan blur horizontal dan vertikal yang terpisah, dan memanfaatkan penyaringan tekstur perangkat keras untuk melakukan blur sembilan-hit dengan hanya lima tekstur yang dibaca pada setiap lintasan. Saya menggambarkan shader ini dalam jawaban Stack Overflow ini .
Jalankan perhitungan deteksi sudut Harris yang sebenarnya menggunakan nilai turunan input kabur. Dalam hal ini, saya sebenarnya menggunakan perhitungan yang dijelaskan oleh Alison Noble di Ph.D. disertasi "Deskripsi Permukaan Gambar". Shader yang menangani ini terlihat seperti berikut:
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
const mediump float harrisConstant = 0.04;
void main()
{
mediump vec3 derivativeElements = texture2D(inputImageTexture, textureCoordinate).rgb;
mediump float derivativeSum = derivativeElements.x + derivativeElements.y;
// This is the Noble variant on the Harris detector, from
// Alison Noble, "Descriptions of Image Surfaces", PhD thesis, Department of Engineering Science, Oxford University 1989, p45.
mediump float harrisIntensity = (derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z)) / (derivativeSum);
// Original Harris detector
// highp float harrisIntensity = derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z) - harrisConstant * derivativeSum * derivativeSum;
gl_FragColor = vec4(vec3(harrisIntensity * 10.0), 1.0);
}
Lakukan penekanan lokal non-maksimum dan terapkan ambang batas untuk menyorot piksel yang lewat. Saya menggunakan shader fragmen berikut untuk sampel delapan piksel di sekitar piksel pusat dan mengidentifikasi apakah itu maksimum dalam pengelompokan itu:
uniform sampler2D inputImageTexture;
varying highp vec2 textureCoordinate;
varying highp vec2 leftTextureCoordinate;
varying highp vec2 rightTextureCoordinate;
varying highp vec2 topTextureCoordinate;
varying highp vec2 topLeftTextureCoordinate;
varying highp vec2 topRightTextureCoordinate;
varying highp vec2 bottomTextureCoordinate;
varying highp vec2 bottomLeftTextureCoordinate;
varying highp vec2 bottomRightTextureCoordinate;
void main()
{
lowp float bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).r;
lowp float bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
lowp float bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
lowp vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
lowp float leftColor = texture2D(inputImageTexture, leftTextureCoordinate).r;
lowp float rightColor = texture2D(inputImageTexture, rightTextureCoordinate).r;
lowp float topColor = texture2D(inputImageTexture, topTextureCoordinate).r;
lowp float topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).r;
lowp float topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
// Use a tiebreaker for pixels to the left and immediately above this one
lowp float multiplier = 1.0 - step(centerColor.r, topColor);
multiplier = multiplier * 1.0 - step(centerColor.r, topLeftColor);
multiplier = multiplier * 1.0 - step(centerColor.r, leftColor);
multiplier = multiplier * 1.0 - step(centerColor.r, bottomLeftColor);
lowp float maxValue = max(centerColor.r, bottomColor);
maxValue = max(maxValue, bottomRightColor);
maxValue = max(maxValue, rightColor);
maxValue = max(maxValue, topRightColor);
gl_FragColor = vec4((centerColor.rgb * step(maxValue, centerColor.r) * multiplier), 1.0);
}
Proses ini menghasilkan peta cornerness dari objek Anda yang terlihat seperti ini:
Poin-poin berikut diidentifikasi sebagai sudut berdasarkan penindasan dan ambang batas yang tidak maksimal:
Dengan ambang yang tepat ditetapkan untuk filter ini, ini dapat mengidentifikasi semua 16 sudut dalam gambar ini, meskipun cenderung menempatkan sudut-sudut piksel atau lebih di dalam tepi sebenarnya dari objek.
Pada iPhone 4, deteksi sudut ini dapat dijalankan pada 20 FPS pada 640x480 frame video yang berasal dari kamera, dan iPhone 4S dapat dengan mudah memproses video dengan ukuran itu pada 60+ FPS. Ini seharusnya jauh lebih baik daripada pemrosesan yang terikat CPU untuk tugas seperti ini, meskipun saat ini proses membaca kembali poin-poinnya adalah terikat-CPU dan sedikit lebih lambat dari yang seharusnya.
Jika Anda ingin melihat ini dalam tindakan, Anda dapat mengambil kode untuk kerangka kerja saya dan menjalankan contoh FilterShowcase yang menyertainya. Contoh deteksi sudut Harris ada berjalan pada video langsung dari kamera perangkat, meskipun seperti yang saya sebutkan pembacaan titik sudut saat ini terjadi pada CPU, yang benar-benar memperlambat ini. Saya pindah ke proses berbasis GPU untuk ini, juga.