Hey là-bas, j'essaie d'accéder aux données brutes de la caméra iPhone à l'aide d'AVCAPTURESession. Je suis le guide fourni par Apple ( Link ici ). p>
Les données brutes de l'échantillon sont au format YUV (ai-je correctement ici sur le format de cadre vidéo brut ??), Comment obtenir directement les données de la composante Y hors des données brutes stockées dans l'échantillon. p>
4 Réponses :
Lors de la configuration de l'AVCaptureVideodataAutUtout qui renvoie les cadres de caméra bruts, vous pouvez définir le format des images à l'aide du code comme suit: Dans ce cas, un format de pixel BGRA est spécifié ( J'ai utilisé ceci pour assortir un format de couleur pour une texture OpenGL ES). Chaque pixel de ce format comporte un octet pour bleu, vert, rouge et alpha, dans cet ordre. Aller avec cela, il est facile de tirer des composants de couleur, mais vous sacrifiez une petite performance en ayant besoin de la conversion de l'espace de couleurs Yuv Caméra-natif YUV. P> Autres espaces de couleurs pris en charge sont Je crois que l'espace de courant par défaut utilisé par une instance AVCaptureVideDataAutUtPut est le YUV 4: 2: 0 Planar Colorspace (sauf sur l'iPhone 3G, où il est yuv 4: 2: 2 entrelacé). Cela signifie qu'il existe deux plans de données d'image contenus dans le cadre de la vidéo, avec l'avion Y arrivant en premier. Pour chaque pixel de votre image résultante, il y a un octet pour la valeur Y à ce pixel. P> Vous obtiendrez dans ces données crues en mettant en œuvre quelque chose comme celui-ci dans votre délégué rappel: P> < Pré> xxx pré> Vous pouvez ensuite comprendre l'emplacement dans les données de l'image pour chaque coordonnée X, Y sur l'image et extraire l'octet de sortie correspondant au composant Y à cette coordonnée. P> < p> Échantillon FindMyicone d'Apple de WWDC 2010 (accessible avec les vidéos) montre comment Procédé des données BGRA brutes de chaque image. J'ai également créé une application d'exemple, que vous pouvez télécharger le code de ici , qui effectue Suivi de l'objet à base de couleurs < / a> Utiliser la vidéo en direct de la caméra de l'iPhone. Les deux montrent comment traiter les données de pixels brutes, mais aucun de ces travaux dans l'espace de couleurs YUV. P> p> kcvpixelormattype_420ypcbcr8biplanarvideorange Code> et
kcvpiixelormattype_420ypcbcr8biplanarfullrange code> sur les nouveaux périphériques et
kcvpixelformattype_422ypcbcr8 code> sur l'iPhone 3G. Le
videorange code> ou
FullRange code> Indique simplement si les octets sont renvoyés entre 16 et 235 pour Y et 16 - 240 pour UV ou 0 - 255 pour chaque composant. P >
@ Brad Larson: si kcvpiixelformattype_420ypcbcr8biplanarvideorange (par défaut de iPhone4) et yuv 420 sont identiques ??
@ASta - Comme je l'ai mentionné ci-dessus, kcvpixelformattype_420ypcbcr8biplanarvideorange code> sur l'iPhone 4 est un espace de courant YUV 4: 2: 0 Planar Colors.
J'ai une autre question.MY codec n'accepte que le format YUV420, mais 420YPCBCR8BIPLANARVIDEORANGE (BIPLANAR) Formatez les données Y (luminance) et les données CBCR (informations de chroma ou de couleur) sont dans deux zones de mémoire distinctes appelées Planes, comment puis-je envoyer à mon CODEC? Toute façon de convertir un seul planar? Si je dois utiliser une conversion de SPL
@ASta - Si votre codec nécessite des données YUV entrelacées, vous devrez peut-être vous déranger vous-même en utilisant le cadre d'accélération ou un shader personnalisé. Cependant, sans violation de la NDA, vous voudrez peut-être lire certaines des notes de publication sur iOS 5.0.
@Bradlarson: cette démonstration de suivi des couleurs ne fonctionne pas maintenant. Veuillez mettre à jour votre réponse. Je veux mettre en œuvre ces choses. Merci... :)
@Metedoshi - Cet exemple d'application a été remplacé par l'exemple de ColorObjectTracking dans ma framework GPuimage: github.com/bradlarson/gpuimage/tree/master/examples/ios/...
En plus de la réponse de Brad, et votre propre code, vous souhaitez considérer les éléments suivants:
Étant donné que votre image dispose de deux plans distincts, la fonction cvpixelbuffergetBaseaddress em> ne retournera pas l'adresse de base de la plan mais plutôt l'adresse de base d'une structure de données supplémentaire. C'est probablement due à la mise en œuvre actuelle que vous obtenez une adresse suffisamment proche du premier plan afin que vous puissiez voir l'image. Mais c'est la raison pour laquelle il se déplace et a des ordures en haut à gauche. La bonne façon de recevoir le premier plan est la suivante: p> une ligne de l'image peut être plus longue que la largeur de l'image (en raison de l'arrondi). C'est pourquoi il existe des fonctions séparées pour obtenir la largeur et le nombre d'octets par ligne. Vous n'avez pas ce problème pour le moment. Mais cela pourrait changer avec la prochaine version d'iOS. Donc, votre code devrait être: p> Veuillez également noter que votre code échoue misérablement sur un iPhone 3G. P> P>
Devrait-il ne pas être cvpixelbuffergetheightyPlane? Juste curieux.
Puisque nous savons que l'avion y a le même nombre de pixels que l'image, cela ne devrait pas faire une différence ici. Mais si nous avons accédé à l'avion UV qui a un nombre réduit de pixels, il serait essentiel d'utiliser CVPIXELBUFFERGETHEELLANE I>.
Cet article illustre quel type de bugs utilise cvpixelbuffergetBaseAddress à la place de cvpixelbuffergetBaseaddressofplane MKONRAD.net/2014/06/24/...
Pour les tampons planaires, CVPixelBuffergetBaseAdress renvoie un pointeur à une structure CVPLANARCOMPONENTINFO, ou NULL si aucune structure de ce type n'est présente. Donc, si votre mémoire tampon est plane, vous devez utiliser CVPIXELBUPERGETBASEADDRESSOFPLANE.
Si vous n'avez besoin que du canal de luminance, je vous recommande d'utiliser le format BGRA, car il s'agit d'une surcharge de conversion. Apple suggère d'utiliser BGRA si vous faites des trucs de rendu, mais vous n'en avez pas besoin pour extraire les informations de luminance. Comme Brad déjà mentionné, le format le plus efficace est le format YUV de la caméra-natif.
Cependant, l'extraction des octets appropriés à partir du tampon d'échantillon est un peu délicat, notamment en ce qui concerne l'iPhone 3G avec son format YUV 422 entrelacé. Donc, voici mon code, qui fonctionne bien avec l'iPhone 3G, 3GS, iPod Touch 4 et iPhone 4s. P>
#pragma mark - #pragma mark AVCaptureVideoDataOutputSampleBufferDelegate Methods #if !(TARGET_IPHONE_SIMULATOR) - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection; { // get image buffer reference CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); // extract needed informations from image buffer CVPixelBufferLockBaseAddress(imageBuffer, 0); size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer); void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer); CGSize resolution = CGSizeMake(CVPixelBufferGetWidth(imageBuffer), CVPixelBufferGetHeight(imageBuffer)); // variables for grayscaleBuffer void *grayscaleBuffer = 0; size_t grayscaleBufferSize = 0; // the pixelFormat differs between iPhone 3G and later models OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer); if (pixelFormat == '2vuy') { // iPhone 3G // kCVPixelFormatType_422YpCbCr8 = '2vuy', /* Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1 */ // copy every second byte (luminance bytes form Y-channel) to new buffer grayscaleBufferSize = bufferSize/2; grayscaleBuffer = malloc(grayscaleBufferSize); if (grayscaleBuffer == NULL) { NSLog(@"ERROR in %@:%@:%d: couldn't allocate memory for grayscaleBuffer!", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__); return nil; } memset(grayscaleBuffer, 0, grayscaleBufferSize); void *sourceMemPos = baseAddress + 1; void *destinationMemPos = grayscaleBuffer; void *destinationEnd = grayscaleBuffer + grayscaleBufferSize; while (destinationMemPos <= destinationEnd) { memcpy(destinationMemPos, sourceMemPos, 1); destinationMemPos += 1; sourceMemPos += 2; } } if (pixelFormat == '420v' || pixelFormat == '420f') { // kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v', // kCVPixelFormatType_420YpCbCr8BiPlanarFullRange = '420f', // Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]). // Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]). // baseAddress points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct // i.e.: Y-channel in this format is in the first third of the buffer! int bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0); baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer,0); grayscaleBufferSize = resolution.height * bytesPerRow ; grayscaleBuffer = malloc(grayscaleBufferSize); if (grayscaleBuffer == NULL) { NSLog(@"ERROR in %@:%@:%d: couldn't allocate memory for grayscaleBuffer!", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__); return nil; } memset(grayscaleBuffer, 0, grayscaleBufferSize); memcpy (grayscaleBuffer, baseAddress, grayscaleBufferSize); } // do whatever you want with the grayscale buffer ... // clean-up free(grayscaleBuffer); } #endif
Bonjour, merci pour la réponse, je suis confronté au même problème. Une chose est que je veux aussi les composants CR et CB et je ne sais pas comment l'obtenir. J'essaie de faire un détecteur de peau et j'ai aussi besoin de ces valeurs comme je l'ai trouvée dans un autre poste. Je l'ai déjà fait utiliser le format de BGRA et la conversion après cela en YCBCR, mais je veux éviter que cette étape de conversion si possible afin d'augmenter le FPS. C'est pourquoi je veux obtenir des valeurs individuelles Y et CR pour chaque pixel de l'image. Des idées?
Comment avez-vous trouvé l'ordre d'octet pour le signal de composant? Le document que j'ai trouvé à partir de Microsoft l'a répertorié comme Y0CRY1CB.
J'ai trouvé un indice dans un fichier d'en-tête Apple. Je suis désolé, mais je ne peux plus vous en dire au fil de l'en-tête.
Ceci est simplement le point culminant du travail acharné de tous les autres, au-dessus et sur d'autres threads, converti en Swift 3 pour quiconque le trouve utile.
Si la solution ci-dessus ne fonctionne pas pour quelqu'un, essayez d'utiliser let bitmapinfo = cgbitmapinfo (Rawvalue: cgimagebyteorderinfo.orderdefault.rawvalue) i> b> let bitmapinfo = cgbitmapinfo (RAWVALUE: CGIMACEALPHAINFO.NONESKIPFIRST.RAWVALUE) I>.
Brad Larson et Codo m'a beaucoup aidé sur ce problème. Avec la combinaison de leurs réponses, je pourrais enfin atteindre mon objectif. Merci beaucoup, Brad Larson et Codo!