방금 Harris 코너 감지를 사용하여 OpenGL ES 2.0에서 이와 같은 것을 구현하고 있었고 완전히 완료되지는 않았지만 지금까지 쉐이더 기반 구현을 공유한다고 생각했습니다. iOS 기반 오픈 소스 프레임 워크 의 일부로이 작업을 수행 했으므로 특정 단계가 어떻게 작동하는지 궁금한 경우 코드를 확인할 수 있습니다.
이를 위해 다음 단계를 사용합니다.
- 벡터 (0.2125, 0.7154, 0.0721)를 사용하여 RGB 값의 내적을 사용하여 이미지를 광도 값으로 줄입니다.
현재 픽셀의 좌우 상하의 픽셀에서 적색 채널 값을 빼서 X 및 Y 미분을 계산합니다. 그런 다음 x 도함수를 적색 채널에 제곱하고 Y 도함수를 녹색 채널에 제곱하고 X 및 Y 도함수의 곱을 파란색 채널에 저장합니다. 이를위한 프래그먼트 셰이더는 다음과 같습니다.
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);
}
여기서 변화는 각 방향의 오프셋 텍스처 좌표입니다. 버텍스 쉐이더에서 미리 계산하여 의존적 인 텍스처 읽기를 제거합니다. 이러한 모바일 GPU에서는 속도가 느립니다.
이 미분 이미지에 가우시안 블러를 적용합니다. 분리 된 수평 및 수직 블러를 사용하고 하드웨어 패스 필터링을 활용하여 각 패스에서 5 회의 텍스처 판독으로 9 회 히트 블러를 수행합니다. 나는 이 스택 셰이더를 이 스택 오버 플로우 답변 에서 설명합니다 .
흐릿한 입력 미분 값을 사용하여 실제 해리스 코너 감지 계산을 실행합니다. 이 경우, 저는 실제로 앨리슨 노블 (Alison Noble)이 박사 학위에 설명 된 계산을 사용하고 있습니다. 논문 "이미지 표면의 설명". 이를 처리하는 셰이더는 다음과 같습니다.
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);
}
로컬 비 최대 억제를 수행하고 임계 값을 적용하여 통과하는 픽셀을 강조 표시하십시오. 다음 조각 셰이더를 사용하여 중앙 픽셀 근처에있는 8 개의 픽셀을 샘플링하고 해당 그룹에서 최대 값인지 여부를 식별합니다.
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);
}
이 프로세스는 다음과 같은 객체로부터 코너 맵을 생성합니다.
다음 포인트는 최대 억제 및 임계 값을 기준으로 코너로 식별됩니다.
이 필터에 대해 적절한 임계 값을 설정하면이 이미지에서 16 개의 모서리를 모두 식별 할 수 있지만 모서리는 객체의 실제 가장자리 내부에 픽셀을 배치하는 경향이 있습니다.
iPhone 4에서이 코너 감지는 카메라에서 나오는 640x480 프레임의 비디오에서 20FPS로 실행할 수 있으며 iPhone 4S는 60+ FPS에서 해당 크기의 비디오를 쉽게 처리 할 수 있습니다. 현재 포인트를 다시 읽는 프로세스는 CPU에 바운드되어 있고 속도는 약간 느리지 만 이와 같은 작업에서는 CPU 바운드 처리보다 훨씬 빠릅니다.