Core Image Concepts
1. crop image
2. color 수정 - white color 정정 같은 것들 수행.
3. color effect 적용 - sepia tone ,gray scale등등
4. 이미지에 Blur 나 샤픈(sharpen) 적용
5. 이미지 합성
6. 이미지에 기하학적인 변형이나 휨 적용
7. color , 채크보더 패턴, 가우스 변환, 기타 패턴 이미지 생성.
8. 이미지나 비디오에 변환 효과 추가.
9. 비디오에 실시간 컬러 조정 제공.
Graphic system에 대한 컨셉적인 이해와 구축의 방향을 잡기에 좋은 그림이 아래의 그림입니다.
Graphics 나 Image , Video등 display와 관련 된 모든 부분은 결국 OpenGL을 이용하도록 설계되어있고, 전반적인 processing의 로드를 GPU와 분담되게 됩니다.
Figure 1-1 gives a general idea of where Core Image fits with other graphics technologies in Mac OS X. Core Image is integrated with these technologies, allowing you to use them together to achieve a wide range of results. For example, you can use Core Image to process images created in Quartz 2D (Core Graphics) and textures created in OpenGL. You can also apply Core Image filters to video played using Core Video.
Core Image and the GPU
OpenGL은 고성능 2D and 3D 그래픽을 위한 업계 표준으로 GPU 를 사용하기 위한 인터페이스 또는 게이트웨이 같은 모듈입니다.
GPU를 이용하여 image processing을 하려면 OpenGL Shading Language를 알아야만 합니다.
<결국 모든 primitive 가 OpenGL 을 사용하게 되면 image processing 역시 GPU의 로드로 넘길 수 있다는 의미로 해석되는 군요.>
현재 대부분의 시스템들은 2D primitive drawing은 CPU를 통한 buffer에 processing 하는 방식과 GPU를 사용하는 방식등 , 혼재되어있는 시스템들이 많다.
이렇게 단일 Graphic module을 사용하지 않아 ,Buffer에 그린 image를 GPU가속을 받기 위해 OpenGL texture로 변환한다거나, 또는 double buffering을 위해 따로 메모리를 잡고 하는 , 중복적인 기능들이 필요하게 되고, GPU 의 도움을 받지 않고 image filtering을 한다거나 변환을 행하는 경우는 CPU에 더더욱 큰 부하를 주게 됩니다.
그런 의미에서 iOS의 그래픽 시스템은 보고 배울만한 교과서 같은 시스템 처럼 느껴집니다.
Graphics module 과 정책에 대해서는 Quartz를 좀 살펴 봐야 하는데, 이는 따로 정리할 필요하 있을것 같습니다.
Filter Clients and Filter Creators
Core Image 는 필터 사용자와 필터 제작자 이렇게 두가지 형태의 개발자를 위해 설계되었습니다.( 모두를 위해서라고 표현해야 하나?)
filter category 는 이펙트 타입 즉, blur, distortion, generator 등등 과 정지 이미지, 비디오 사각형이 아닌 픽셀 을 위한 것들이 명시됩니다.
아래의 대표적인 필터의 컴포넌트를 자세히 들여다 본것입니다.
outputImage 메소드는 이미지를 만들어는 것이 가능하도록 계산 결과들을 모으고 저장한다. 그러나 실제로 Core Image를 이미지 프로세싱 하지 않는다.
Core Image는 lazy evaluation을 사용하기 때문입니다.
< 어떤 작업을 되도록 늦추고 늦춰서 꼭 필요해지는 최종 순간에 처리하는 것을 의미합니다..>
다른게 표현하면, processing된 pixel을 최종 타겟에 실제로 칠해야 하는 시점이 오기 전까지는 Core Image가 image processing하는 일은 없다고 할수 있겠군요.
outputImage 메소드는 Core Image가 필요로 하는 계산 값들을 모으거나 , CIImage에 계산 값들을 저장하는 것 밖에 없다. 실제 이미지는 가 만들어지는 것은 명시적으로 image drawing 메소드가 불렸을 때 뿐이다. (drawImage:atPoint:fromRect 나 drawImage:inRect:fromRect 같은 메소드)
Core Image stores the calculations until your application issues a command to draw the image. At that time, Core Image calculates the results. Lazy evaluation is one of the practices that makes Core Image fast and efficient. At rendering time, Core Image can see if more than one filter needs to be applied to an image. If so, it can concatenate multiple “recipes” into one operation, which means each pixel is processed once rather than many times. Figure 1-3 illustrates how lazy evaluation can make image processing more efficient for multiple operations. The final image is a scaled-down version of the original. For the case of a large image, applying color adjustment before scaling down the image requires more processing power than scaling down the image and then applying color adjustment. Because Core Image waits until the last possible moment to apply filters, it can perform these operations in reverse order, which is more efficient.
For the filter creator, the most exciting component of a filter is the kernel, which is at the heart of every filter. The kernel specifies the calculations that are performed on each source image pixel. Kernel calculations can be very simple or complex. A very simple kernel for a “do nothing” filter could simply return the source pixel:
destination pixel = source pixel
Filter creators use a variant of OpenGL Shading Language (glslang) to specify per-pixel calculations. (See Core Image Kernel Language Reference.) The kernel is opaque to a filter client. A filter can actually use several kernel routines, passing the output of one to the input of another. For instructions on how to write a custom filter, see “Creating a Custom Filter.”
Filter creators can make their custom filters available to any application by packaging them as a plug-in, or image unit, using the architecture specified by the NSBundle
class. An image unit can contain more than one filter, as shown in Figure 1-4. For example, you could write a set of filters that perform different kinds of edge detection and package them as a single image unit. Filter clients can use the Core Image API to load the image unit and to obtain a list of the filters contained in that image unit. See “Loading Image Units” for basic information. See Image Unit Tutorial for in-depth examples and detailed information on writing filters and packaging them as standalone image units.
The Processing Path
Figure 1-5 shows the pixel processing path for a filter that operates on two sources images. Source images are always specified as CIImage
objects. Core Image provides a variety of ways to get image data. You can supply a URL to an image, read raw image data (using the NSData
class), or convert a Quartz 2D image (CGContextRef
), an OpenGL texture, or a Core Video image buffer (CVImageBufferRef
) to a CIImage
object.
Note that the actual number of input images, and whether or not the filter requires an input image, depends on the filter. Filters are very flexible—a filter can:
Work without an input image. Some filters generate an image based on input parameters that aren’t images. (For example, see the
CICheckerboardGenerator
andCIConstantColorGenerator
filters in Core Image Filter Reference.)Require one image. (For example, see the
CIColorPosterize
andCICMYKHalftone
filters in Core Image Filter Reference.)Require two or more images. Filters that composite images or use the values in one image to control how the pixels in another image are processed typically require two or more images. One input image can act as a shading image, an image mask, a background image, or provide a source of lookup values that control some aspect of how the other image is processed. (For example, see the
CIShadedMaterial
filter in Core Image Filter Reference.)
When you process an image, it is your responsibility to create a CIImage
object that contains the appropriate input data.
Pixels from each source image are fetched by a CISampler
object, or simply a sampler. As its name suggests, a sampler retrieves samples of an image and provides them to a kernel. A filter creator provides a sampler for each source image. Filter clients don’t need to know anything about samplers.
A sampler defines:
A coordinate transform, which can be the identity transform if no transformation is needed.
An interpolation mode, which can be nearest neighbor sampling or bilinear interpolation (which is the default).
A wrapping mode that specifies how to produce pixels when the sampled area is outside of the source image—either to use transparent black or clamp to the extent.
The filter creator defines the per-pixel image processing calculations in the kernel, but Core Image handles the actual implementation of those calculations. Core Image determines whether the calculations are performed using the GPU or the CPU. Core Image implements hardware rasterization through OpenGL. It implements software rasterization through an emulation environment specifically tuned for evaluating fragment programs with nonprojective texture lookups over large quadrilaterals (quads).
Although the pixel processing path is from source image to destination, the calculation path that Core Image uses begins at the destination and works its way back to the source pixels, as shown in Figure 1-6. This backward calculation might seem unwieldy, but it actually minimizes the number of pixels used in any calculation. The alternative, which Core Image does not use, is the brute force method of processing all source pixels, then later deciding what’s needed for the destination. Let’s take a closer look at Figure 1-6.
Assume that the filter in Figure 1-6 performs some kind of compositing operation, such as source-over compositing. The filter client wants to overlap the two images, so that only a small portion of each image is composited to achieve the result shown at the left side of the figure. By looking ahead to what the destination ought to be, Core Image can determine which data from the source images affect the final image and then restrict calculations only to those source pixels. As a result, the samplers fetch samples only from shaded areas in the source images shown in Figure 1-6.
Note the box in the figure that’s labeled domain of definition. The domain of definition is simply a way to further restrict calculations. It is an area outside of which all pixels are transparent (that is, the alpha component is equal to 0). In this example, the domain of definition coincides exactly with the destination image. Core Image lets you supply a CIFilterShape
object to define this area. TheCIFilterShape
class provides a number of methods that can define rectangular shapes, transform shapes, and perform inset, union, and intersection operations on shapes. For example, if you define a filter shape using a rectangle that is smaller than the shaded area shown in Figure 1-6, then Core Image uses that information to further restrict the source pixels used in the calculation.
Core Image promotes efficient processing in other ways. It performs intelligent caching and compiler optimizations that make it well suited for such tasks as real-time video control. It caches intermediate results for any data set that is evaluated repeatedly. Core Image evicts data in least-recently-used order whenever adding a new image would cause the cache to grow too large, which means objects that are reused frequently remain in the cache, while those used once in a while might be moved in and out of the cache as needed. Your application benefits from Core Image caching without needing to know the details of how caching is implemented. However, you get the best performance by reusing objects (images, contexts, and so forth) whenever you can.
Core Image also gets great performance by using traditional compilation techniques at the kernel and pass levels. The method Core Image uses to allocate registers minimizes the number of temporary registers (per kernel) and temporary pixel buffers (per filter graph). The compiler performs CSE and peephole optimization and automatically distinguishes between reading data-dependent textures, which are based on previous calculations, and those that are not data-dependent. Again, you don’t need to concern yourself with the details of the compilation techniques. The important point is that Core Image is hardware savvy; it uses the power of the GPU whenever it can, and it does so in smart ways.
Coordinate Spaces
Core Image performs operations in a device-independent working space, similar in concept to what’s shown in Figure 1-7. The Core Image working space is, in theory, infinite in extent. A point in working space is represented by a coordinate pair (x, y), where x represents the location along the horizontal axis and y represents the location along the vertical axis. Coordinates are floating-point values. By default, the origin is point (0,0).
When Core Image reads images, it translates the pixel locations into device-independent working space coordinates. When it is time to display a processed image, Core Image translates the working space coordinates to the appropriate coordinates for the destination, such as a display.
When you write your own filters, you need to be familiar with two coordinate spaces—the destination coordinate space and the sampler space. The destination coordinate space represents the image you are rendering to. The sampler space represents what you are texturing from (another image, a lookup table, and so on). You obtain the current location in destination space using the destCoord
function whereas the samplerCoord
function provides the current location in sample space. (See Core Image Kernel Language Reference.)
Keep in mind that if your source data is tiled, the sampler coordinates have an offset (dx/dy). If your sample coordinates have an offset, it may be necessary for you to convert the destination location to the sampler location using the function samplerTransform
.
The Region of Interest
Although not explicitly labeled in Figure 1-6, the shaded area in each of the source images is the region of interest for samplers depicted in the figure. The region of interest, or ROI, defines the area in the source from which a sampler takes pixel information to provide to the kernel for processing. If you are a filter client, you don’t need to concern yourself with the ROI. But if you are a filter creator, you’ll want to understand the relationship between the region of interest and the domain of definition.
Recall that the domain of definition describes the bounding shape of a filter. In theory, this shape can be without bounds. Consider, for example, a filter that creates a repeating pattern that could extend to infinity.
The ROI and the domain of definition can relate to each other in the following ways:
They coincide exactly—there is a 1:1 mapping between source and destination. For example, a hue filter processes a pixel from the working space coordinate (r,s) in the ROI to produce a pixel at the working space coordinate (r,s) in the domain of definition.
They are dependent on each other, but modulated in some way. Some of the most interesting filters—blur and distortion, for example—use many source pixels in the calculation of one destination pixel. For example, a distortion filter might use a pixel (r,s) and its neighbors from the working coordinate space in the ROI to produce a single pixel (r,s) in the domain of definition.
The domain of definition is calculated from values in a lookup table that are provided by the sampler. The location of values in the map or table are unrelated to the working space coordinates in the source image and the destination. A value located at (r,s) in a shading image does not need to be the value that produces a pixel at the working space coordinate (r,s) in the domain of definition. Many filters use values provided in a shading image or lookup table in combination with an image source. For example, a color ramp or a table that approximates a function, such as the
arcsin
function, provides values that are unrelated to the notion of working coordinates.
Unless otherwise instructed, Core Image assumes that the ROI and the domain of definition coincide. If you write a filter for which this assumption doesn’t hold, you need to provide Core Image with a routine that calculates the ROI for a particular sampler.
See “Supplying an ROI Function” for more information.
Executable and Nonexecutable Filters
You can categorize custom Core Image filters on the basis of whether or not they require an auxiliary binary executable to be loaded into the address space of the client application. As you use the Core Image API, you’ll notice that these are simply referred to as executable and nonexecutable. Filter creators can choose to write either kind of filter. Filter clients can choose to use only nonexecutable or to use both kinds of filters.
Security is the primary motivation for distinguishing CPU executable and CPU nonexecutable filters. Nonexecutable filters consist only of a Core Image kernel program to describe the filter operation. In contrast, an executable filter also contains machine code that runs on the CPU. Core Image kernel programs run within a restricted environment and cannot pose as a virus, Trojan horse, or other security threat, whereas arbitrary code that runs on the CPU can.
Nonexecutable filters have special requirements, one of which is that nonexecutable filters must be packaged as part of an image unit. Filter creators can read “Writing Nonexecutable Filters” for more information. Filter clients can find information on loading each kind of filter in “Loading Image Units.”
Color Components and Premultiplied Alpha
Premultiplied alpha is a term used to describe a source color, the components of which have already been multiplied by an alpha value. Premultiplying speeds up the rendering of an image by eliminating the need to perform a multiplication operation for each color component. For example, in an RGB color space, rendering an image with premultiplied alpha eliminates three multiplication operations (red times alpha, green times alpha, and blue times alpha) for each pixel in the image.
Filter creators must supply Core Image with color components that are premultiplied by the alpha value. Otherwise, the filter behaves as if the alpha value for a color component is 1.0. Making sure color components are premultiplied is important for filters that manipulate color.
By default, Core Image assumes that processing nodes are 128 bits-per-pixel, linear light, premultiplied RGBA floating-point values that use the GenericRGB color space. You can specify a different working color space by providing a Quartz 2D CGColorSpace object. Note that the working color space must be RGB-based. If you have YUV data as input (or other data that is not RGB-based), you can use ColorSync functions to convert to the working color space. (See Quartz 2D Programming Guide for information on creating and using CGColorspace objects.)
With 8-bit YUV 4:2:2 sources, Core Image can process 240 HD layers per gigabyte. Eight-bit YUV is the native color format for video source such as DV, MPEG, uncompressed D1, and JPEG. You need to convert YUV color spaces to an RGB color space for Core Image.
'개발 Note > UI Framework 개발하기' 카테고리의 다른 글
Good Language & Good Framework (2): 좋은 언어와 좋은 프래임워크란? (0) | 2016.02.12 |
---|---|
stdafx.h 를 없애보자! (0) | 2011.08.18 |
CoreAnimation in iOS (0) | 2011.07.13 |
key - value 관리 (0) | 2011.06.08 |
[애자일] 릴리즈 계획 과정에서 가장 중요한 것들 (0) | 2010.10.29 |