正如标题所示,我在行中发生错误时遇到问题
targetTexture.ReadPixels(new Rect(0, 0, cameraResolution.width, cameraResolution.height), 0, 0);
错误:
调用ReadPixels从系统帧缓冲区读取像素,而不是在绘图帧内。 UnityEngine.Texture2D:ReadPixels(Rect,Int32,Int32)
正如我从其他帖子中了解到的,解决此问题的一种方法是制作一个Ienumerator方法,该方法会产生返回新的WaitForSeconds或其他东西,并将其称为:StartCoroutine(methodname)
,以便及时加载帧以便读取像素-ish。
我没有得到的是在下面的代码中这个方法最有意义的地方。哪个部分无法及时加载?
PhotoCapture photoCaptureObject = null;
Texture2D targetTexture = null;
public string path = "";
CameraParameters cameraParameters = new CameraParameters();
private void Awake()
{
var cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
// Create a PhotoCapture object
PhotoCapture.CreateAsync(false, captureObject =>
{
photoCaptureObject = captureObject;
cameraParameters.hologramOpacity = 0.0f;
cameraParameters.cameraResolutionWidth = cameraResolution.width;
cameraParameters.cameraResolutionHeight = cameraResolution.height;
cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;
});
}
private void Update()
{
// if not initialized yet don't take input
if (photoCaptureObject == null) return;
if (Input.GetKey("k") || Input.GetKey("k"))
{
Debug.Log("k was pressed");
VuforiaBehaviour.Instance.gameObject.SetActive(false);
// Activate the camera
photoCaptureObject.StartPhotoModeAsync(cameraParameters, result =>
{
if (result.success)
{
// Take a picture
photoCaptureObject.TakePhotoAsync(OnCapturedPhotoToMemory);
}
else
{
Debug.LogError("Couldn't start photo mode!", this);
}
});
}
}
private static string FileName(int width, int height)
{
return $"screen_{width}x{height}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png";
}
private void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
// Copy the raw image data into the target texture
photoCaptureFrame.UploadImageDataToTexture(targetTexture);
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
targetTexture.ReadPixels(new Rect(0, 0, cameraResolution.width, cameraResolution.height), 0, 0);
targetTexture.Apply();
byte[] bytes = targetTexture.EncodeToPNG();
string filename = FileName(Convert.ToInt32(targetTexture.width), Convert.ToInt32(targetTexture.height));
//save to folder under assets
File.WriteAllBytes(Application.streamingAssetsPath + "/Snapshots/" + filename, bytes);
Debug.Log("The picture was uploaded");
// Deactivate the camera
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
private void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
// Shutdown the photo capture resource
VuforiaBehaviour.Instance.gameObject.SetActive(true);
photoCaptureObject.Dispose();
photoCaptureObject = null;
}
很抱歉,如果这与this重复,例如。
编辑
当我到达那一点时,this可能会有用。
这样我根本不需要这三条线吗?
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
targetTexture.ReadPixels(new Rect(0, 0, cameraResolution.width, cameraResolution.height), 0, 0);
targetTexture.Apply();
正如评论中所写,使用这三行之间的区别并不是保存的照片具有黑色背景+ AR-GUI。没有上面第二行代码的是带有AR-GUI的照片,但背景是我的计算机网络摄像头的实时流。而且我真的不想看电脑网络摄像头,而是HoloLens看到的东西。
你的三行
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
targetTexture.ReadPixels(new Rect(0, 0, cameraResolution.width, cameraResolution.height), 0, 0);
targetTexture.Apply();
对我来说没什么意义。 Texture2D.ReadPixels用于创建屏幕截图,以便用屏幕截图覆盖您从PhotoCapture
收到的纹理? (由于相机分辨率非常可能,尺寸也不正确!=屏幕分辨率。)
这也是原因
正如评论中所写,使用这三行之间的区别并不是保存的照片具有黑色背景+ AR-GUI。
做完之后
photoCaptureFrame.UploadImageDataToTexture(targetTexture);
你已经从Texture2D
的PhotoCapture
收到了targetTexture
。
我想你可能把它与用于获取给定Texture2D.GetPixels的像素数据的Texture2D
混淆了。
我想最后从中心裁剪拍摄的照片,我想这个代码行可能有可能吗?在0,0以外的其他像素处开始新的rect
你真正想要的是如你在评论中提到的那样从中心裁剪收到的Texture2D
。你可以使用GetPixels(int x, int y, int blockWidth, int blockHeight, int miplevel)做到这一点,Texture2D
用于切出给定public static Texture2D CropAroundCenter(Texture2D input, Vector2Int newSize)
{
if(input.width < newSize.x || input.height < newSize.y)
{
Debug.LogError("You can't cut out an area of an image which is bigger than the image itself!", this);
return null;
}
// get the pixel coordinate of the center of the input texture
var center = new Vector2Int(input.width / 2, input.height / 2);
// Get pixels around center
// Get Pixels starts width 0,0 in the bottom left corner
// so as the name says, center.x,center.y would get the pixel in the center
// we want to start getting pixels from center - half of the newSize
//
// than from starting there we want to read newSize pixels in both dimensions
var pixels = input.GetPixels(center.x - newSize.x / 2, center.y - newSize.y / 2, newSize.x, newSize.y, 0);
// Create a new texture with newSize
var output = new Texture2D(newSize.x, newSize.y);
output.SetPixels(pixels);
output.Apply();
return output;
}
的某个区域
GetPixels
private void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
// Copy the raw image data into the target texture
photoCaptureFrame.UploadImageDataToTexture(targetTexture);
// for example take only half of the textures width and height
targetTexture = CropAroundCenter(targetTexture, new Vector2Int(targetTexture.width / 2, targetTexture.height / 2);
byte[] bytes = targetTexture.EncodeToPNG();
string filename = FileName(Convert.ToInt32(targetTexture.width), Convert.ToInt32(targetTexture.height));
//save to folder under assets
File.WriteAllBytes(Application.streamingAssetsPath + "/Snapshots/" + filename, bytes);
Debug.Log("The picture was uploaded");
// Deactivate the camera
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
而不是用它
extension method
或者你可以使它成为一个static class
在一个分开的public static class Texture2DExtensions
{
public static void CropAroundCenter(this Texture2D input, Vector2Int newSize)
{
if (input.width < newSize.x || input.height < newSize.y)
{
Debug.LogError("You can't cut out an area of an image which is bigger than the image itself!");
return;
}
// get the pixel coordinate of the center of the input texture
var center = new Vector2Int(input.width / 2, input.height / 2);
// Get pixels around center
// Get Pixels starts width 0,0 in the bottom left corner
// so as the name says, center.x,center.y would get the pixel in the center
// we want to start getting pixels from center - half of the newSize
//
// than from starting there we want to read newSize pixels in both dimensions
var pixels = input.GetPixels(center.x - newSize.x / 2, center.y - newSize.y / 2, newSize.x, newSize.y, 0);
// Resize the texture (creating a new one didn't work)
input.Resize(newSize.x, newSize.y);
input.SetPixels(pixels);
input.Apply(true);
}
}
喜欢
targetTexture.CropAroundCenter(new Vector2Int(targetTexture.width / 2, targetTexture.height / 2));
并使用它代替
UploadImageDataToTexture
注意:
CopyRawImageDataIntoBuffer:如果您在CameraParameters中指定了BGRA32格式,则只能使用此方法。
幸运的是你无论如何都要使用它;)
请记住,此操作将在主线程上发生,因此很慢。
然而,唯一的选择是UploadImageDataToTexture
并在另一个线程或外部生成纹理,所以我会说可以留在Y-Axis
;)
和
拍摄的图像也会在HoloLens上翻转。您可以使用自定义着色器重定向图像。
通过翻转它们实际上意味着纹理的X-Axis
是颠倒的。 public static class Texture2DExtensions
{
public static void CropAroundCenter(){....}
public static void FlipVertically(this Texture2D texture)
{
var pixels = texture.GetPixels();
var flippedPixels = new Color[pixels.Length];
// These for loops are for running through each individual pixel and
// write them with inverted Y coordinates into the flippedPixels
for (var x = 0; x < texture.width; x++)
{
for (var y = 0; y < texture.height; y++)
{
var pixelIndex = x + y * texture.width;
var flippedIndex = x + (texture.height - 1 - y) * texture.width;
flippedPixels[flippedIndex] = pixels[pixelIndex];
}
}
texture.SetPixels(flippedPixels);
texture.Apply();
}
}
是正确的。
要垂直翻转纹理,您可以使用第二种扩展方法:
targetTexture.FlipVertically();
并使用它
结果:(对于此示例和给定的纹理,我使用FlipVertically和cropp每秒的大小的一半,但它对于拍摄的图片应该相同。)
http://developer.vuforia.com/sites/default/files/sample-apps/targets/imagetargets_targets.pdf
图像来源:if (Input.GetKey("k") || Input.GetKey("k"))
更新
你的按钮问题:
不要用
GetKey
首先,你要检查完全相同的条件两次。并且当钥匙保持按下时,if (Input.GetKeyDown("k"))
会向每一帧发射。而是使用
qazxswpoi
它只发射一次。我猜Vuforia和PhotoCapture存在问题,因为您的原始版本经常被解雇,也许您有一些并发的PhotoCapture流程......