커널
Kernel (image processing) - Wikipedia
From Wikipedia, the free encyclopedia Matrix used in image processing to alter an image In image processing, a kernel, convolution matrix, or mask is a small matrix used for blurring, sharpening, embossing, edge detection, and more. This is accomplished by
en.wikipedia.org
- Box Blur → 흐리게 만들어준다.
- Gaussian Blur → 흐리게 만들어준다.
Weights: [0.0545f, 0.2442f, 0.4026f, 0.2442f, 0.0545f]
- Bloom Filter → 명암 대비를 더 크게 만들어준다.
- 원본 이미지 + 블러 이미
- Relative Luminance Y = 0.2126R + 0.7152G + 0.0722*B
Convolution
(0,0) 좌표의 픽셀을 Convolution하는 방법
- 음수의 영역의 픽셀을 가장 인접한 픽셀의 데이터로 대입한다.
Separable Convolution
1차원 Convolution을 가로 방향으로 진행 후, 세로 방향으로 진행
블룸 효과를 준 레몬 침착맨
원본 이미지
침착맨 레몬의 효능 장패드 ㅣ 마플샵
침착맨 레몬의 효능 장패드, 레몬의 효능 장패드 22,000원
marpple.shop
Github Repository
GitHub - TaeYoon17/MetalGraphics: 그래픽스 기술을 Metal API로 구현하기
그래픽스 기술을 Metal API로 구현하기. Contribute to TaeYoon17/MetalGraphics development by creating an account on GitHub.
github.com
핵심 개념
- SIMD 연산
- CIImage
- CIImage로 이미지 Pixel들에 접근해서 Vertex 배열로 변환함
- CGContext
- data , width, height, bitsPerComponent, bytesPerRow
그래픽 컨텍스트에는 대상 페이지가 애플리케이션의 창, 비트맵 이미지, PDF 문서 또는 프린터인지 여부에 관계없이 페이지의 페인트를 대상에 렌더링하는 데 필요한 그리기 매개변수와 모든 디바이스별 정보가 포함되어 있습니다.
- CGColorSpaceCreateDeviceRGB
기기에 맞는 RGB 값을 생성하는 메서드
사용자 이미지를 Position,RGB 정보로 담긴 Vertex로 만들고 Metal로 그리기
- 사용자 이미지를 CIImage로 가져오기
- CIImage로 CGImage를 생성 후, CFData로 변환
- CFData의 포인터 주소 배열 가져오기
⇒ 이미지가 2차원에서 1차원 배열로 변환됨
- Metal Shader에서 사용할 Vertex 배열로 변환하기
- 원본 이미지 좌표게에서 메탈 좌표계로 변환
- 원본 색상 값에서 메탈 색상 값으로 변환
- 원본 이미지에서 추출한 Vertex 배열 값에 Bloom 필터 효과 주기
- Metal Shader로 그리기
메탈 좌표계와 이미지 방향 맞추기
CIImage의 좌표계는 다행히 Metal과 방향이 같다. 좌표 변환을 위한 Reverse 작업은 없음
핵심 코드
let pointer = CFDataGetBytePtr(data) // CIImage를 CFData의 포인터로 저장함
// 이미지(CIImage) Coordinates to Metal Coordinates
for y in 0..<height {
for x in 0..<width {
let pixelInfo = y * bytesPerRow + x * bytesPerPixel
let red = Float(pointer![pixelInfo]) / 255.0
let green = Float(pointer![pixelInfo + 1]) / 255.0
let blue = Float(pointer![pixelInfo + 2]) / 255.0
// 원본 이미지의 Row 배열이 [1,2,3,4,5]라면 현제 Vertex에 담긴 배열은 [5,4,3,2,1]이 된다.
// 메탈은 하나의 Row를 동시에 읽기 때문에 y좌표만 반대로 바꾸어서(Reverse) 2차원 배열에 담는다.
vetecies.append(Vertex(position: .init(x: 2*(Float(x) / Float(width) - 0.5),
y: -2*(Float(y) / Float(height) - 0.5)),
color: [red,green,blue,1]))
}
}
Bloom 효과 만들기
inout
을 이용해서 Vertex 값을 참조해서 연산하기- simd 메서드를 통해 빠르게 연산시키기
- Bloom 효과 = 원본을 GaussianBlur 처리한 이미지 + 원본에서 임계값 이하는 Black 처리한 이미지
문제점
- 시간을 계산하니 SIMD를 사용하지만, CPU로 모든 Bloom 그래픽 처리를 완료한 후 Metal로 그리는 로직으로 약 10초!!를 연산을 기다려야한다.
let startTime = DispatchTime.now()
makeBloom(vertices: &vetecies, width: width, height: height, th: 0.33,weight: 0.2)
let endTime = DispatchTime.now()
let nanoTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
let executionTime = Double(nanoTime) / 1_000_000_000 // 초 단위로 변환
print("Execution time: \(executionTime) seconds")
코드
'Metal' 카테고리의 다른 글
무게 중심 좌표계, Barycentric coordinates (0) | 2024.04.30 |
---|---|
Perspective Projection & Phong Shading (0) | 2024.04.22 |
RayTracing으로 삼각형 그리기 (0) | 2024.04.08 |
Raytracing으로 구 그리기 (0) | 2024.03.31 |
댓글