CF 549D. Haar Features(神奇,不知道怎么推出来的)

本文介绍了一种简化版的人脸检测算法中特征计算方法,该算法由Viola和Jones于2001年提出,使用Haar特征进行实时人脸检测。文章详细解释了如何通过最少的操作数来计算特定特征值,利用前缀矩形的概念减少计算复杂度。

The first algorithm for detecting a face on the image working in realtime was developed by Paul Viola and Michael Jones in 2001. A part of the algorithm is a procedure that computes Haar features. As part of this task, we consider a simplified model of this concept.

Let's consider a rectangular image that is represented with a table of size n × m. The table elements are integers that specify the brightness of each pixel in the image.

feature also is a rectangular table of size n × m. Each cell of a feature is painted black or white.

To calculate the value of the given feature at the given image, you must perform the following steps. First the table of the feature is put over the table of the image (without rotations or reflections), thus each pixel is entirely covered with either black or white cell. The value of a feature in the image is the value of W - B, where W is the total brightness of the pixels in the image, covered with white feature cells, and B is the total brightness of the pixels covered with black feature cells.

Some examples of the most popular Haar features are given below.

Your task is to determine the number of operations that are required to calculate the feature by using the so-called prefix rectangles.

prefix rectangle is any rectangle on the image, the upper left corner of which coincides with the upper left corner of the image.

You have a variable value, whose value is initially zero. In one operation you can count the sum of pixel values ​​at any prefix rectangle, multiply it by any integer and add to variable value.

You are given a feature. It is necessary to calculate the minimum number of operations required to calculate the values of this attribute at an arbitrary image. For a better understanding of the statement, read the explanation of the first sample.

Input

The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 100) — the number of rows and columns in the feature.

Next n lines contain the description of the feature. Each line consists of m characters, the j-th character of the i-th line equals to "W", if this element of the feature is white and "B" if it is black.

Output

Print a single number — the minimum number of operations that you need to make to calculate the value of the feature.

Sample test(s)
input
6 8
BBBBBBBB
BBBBBBBB
BBBBBBBB
WWWWWWWW
WWWWWWWW
WWWWWWWW
output
2
input
3 3
WBW
BWW
WWW
output
4
input
3 6
WWBBWW
WWBBWW
WWBBWW
output
3
input
4 4
BBBB
BBBB
BBBB
BBBW
output
4
Note

The first sample corresponds to feature B, the one shown in the picture. The value of this feature in an image of size 6 × 8 equals to the difference of the total brightness of the pixels in the lower and upper half of the image. To calculate its value, perform the following two operations:

  1. add the sum of pixels in the prefix rectangle with the lower right corner in the 6-th row and 8-th column with coefficient 1 to the variable value (the rectangle is indicated by a red frame);
  2. add the number of pixels in the prefix rectangle with the lower right corner in the 3-rd row and 8-th column with coefficient  - 2 and variable value.

Thus, all the pixels in the lower three rows of the image will be included with factor 1, and all pixels in the upper three rows of the image will be included with factor 1 - 2 =  - 1, as required.

http://codeforces.com/contest/549/problem/D

#include<stdio.h>
int n,m;
char a[106][106];
int b[106][106];
int ans;
int main(){
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++){
		scanf("%s",a[i]);
	}
	for(i=0;i<n;i++){
		for(j=0;j<m;j++){
			if(a[i][j]=='W')b[i][j]=1;
			else b[i][j]=-1;
		}
	}
	ans=0;
	for(i=0;i<n;i++){
		for(j=0;j<m;j++){
			if(b[i][j]+b[i+1][j+1]!=b[i][j+1]+b[i+1][j])ans++;
		}
	}
	printf("%d",ans);
}


<think>我们被要求使用OpenCV在Android应用中加载一个存储在raw资源目录下的Haar级联分类器文件(haarcascade_frontalface_default.xml)。 步骤: 1. 将XML文件放在res/raw目录下(如果没有raw目录,则创建它)。 2. 在代码中,我们需要获取这个资源的输入流,然后使用OpenCV的CascadeClassifier加载它。 但是注意:OpenCV的CascadeClassifier通常需要文件路径。然而,当我们把文件放在raw目录中时,我们无法直接获取文件路径(因为资源是压缩的)。因此,我们需要先将文件复制到应用的内部存储或外部存储,然后从那里加载。 具体步骤: a) 将XML文件从res/raw复制到内部存储的某个目录(例如files目录)。 b) 使用复制后的文件路径来初始化CascadeClassifier。 注意:为了避免每次启动应用都复制,我们可以检查文件是否已经存在。 另外,我们也可以将文件放在assets目录下,然后以类似的方式处理。 但是,根据引用[1]中的描述,他们是将xml文件拷贝到raw目录中。所以我们这里按照raw目录来处理。 实现代码示例: 1. 在res目录下创建raw目录,并将haarcascade_frontalface_default.xml文件放入其中。 2. 在代码中: 首先,我们需要一个方法将raw资源复制到内部存储: ```java private void copyRawResourceToFile(int resourceId, String outputFileName) { InputStream inputStream = getResources().openRawResource(resourceId); OutputStream outputStream = null; try { outputStream = new FileOutputStream(outputFileName); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) outputStream.close(); if (inputStream != null) inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 然后,在初始化OpenCV后,我们进行复制和加载: ```java // 假设我们的资源文件名为:haarcascade_frontalface_default.xml,在raw目录下,资源ID为R.raw.haarcascade_frontalface_default String cascadeDir = getDir("cascade", Context.MODE_PRIVATE).getAbsolutePath(); String cascadeFilePath = cascadeDir + "/haarcascade_frontalface_default.xml"; // 如果文件存在,则复制 File cascadeFile = new File(cascadeFilePath); if (!cascadeFile.exists()) { copyRawResourceToFile(R.raw.haarcascade_frontalface_default, cascadeFilePath); } // 加载级联分类器 CascadeClassifier faceDetector = new CascadeClassifier(); if (faceDetector.load(cascadeFilePath)) { // 加载成功 } else { // 加载失败 Log.e(TAG, "Failed to load cascade classifier"); faceDetector = null; } ``` 注意:getDir("cascade", Context.MODE_PRIVATE)会在应用的内部存储中创建一个名为"cascade"的目录(如果存在),并返回该目录的绝对路径。 3. 使用faceDetector进行人脸检测。 另外,我们也可以将文件放在assets目录下,然后使用AssetManager来复制。但这里用户要求使用R.raw,所以我们使用raw目录。 重要:在复制完成后,我们可以使用这个cascadeFilePath来初始化CascadeClassifier。 但是,请注意,每次应用更新时,如果资源文件有变化,我们可能需要重新复制。或者我们可以检查文件的版本等。过通常我们只需要在第一次运行或者文件存在时复制。 另外,由于内部存储空间是应用私有的,所以用担心文件被其他应用修改。 以上就是在Android中使用OpenCV加载raw资源目录下的级联分类器的方法。 相关问题: 1. 如何提高OpenCV在Android上的人脸检测速度? 2. 除了Haar级联分类器,OpenCV还支持哪些人脸检测方法? 3. 在Android上使用OpenCV进行人脸检测时,如何处理相机的实时视频流?</think>### Android OpenCV 加载 R.raw.haarcascade_frontalface_default 方法 在 Android 中使用 OpenCV 加载 `R.raw.haarcascade_frontalface_default` 资源进行人脸检测,需按以下步骤操作: #### 1. **准备资源文件** - 将 `haarcascade_frontalface_default.xml` 放入 `res/raw/` 目录(若目录存在需手动创建) - 确保资源 ID 正确:`R.raw.haarcascade_frontalface_default` #### 2. **关键代码实现** ```java import org.opencv.android.Utils; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.imgproc.Imgproc; import org.opencv.objdetect.CascadeClassifier; // 步骤1:将资源文件复制到应用内部存储 private CascadeClassifier initFaceDetector(Context context) { try { // 创建内部存储路径 File cascadeDir = context.getDir("cascade", Context.MODE_PRIVATE); File cascadeFile = new File(cascadeDir, "haarcascade_frontalface_default.xml"); // 复制资源文件(首次运行或更新时) if (!cascadeFile.exists() || isResourceUpdated(context)) { InputStream is = context.getResources().openRawResource(R.raw.haarcascade_frontalface_default); FileOutputStream os = new FileOutputStream(cascadeFile); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } is.close(); os.close(); } // 步骤2:加载级联分类器 CascadeClassifier faceDetector = new CascadeClassifier(); if (faceDetector.load(cascadeFile.getAbsolutePath())) { return faceDetector; } } catch (IOException e) { Log.e("OpenCV", "Error loading cascade: " + e.getMessage()); } return null; } // 步骤3:执行人脸检测 private void detectFaces(Mat rgbaMat, CascadeClassifier faceDetector) { Mat grayMat = new Mat(); Imgproc.cvtColor(rgbaMat, grayMat, Imgproc.COLOR_RGBA2GRAY); // 转为灰度图 MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale( grayMat, // 输入图像 faceDetections, // 检测结果 1.1, // 缩放因子 3, // 最小邻居数 0, // 标志(保留默认) new Size(30, 30), // 最小人脸尺寸 new Size() // 最大人脸尺寸(空表示无限制) ); // 绘制检测框 for (Rect rect : faceDetections.toArray()) { Imgproc.rectangle(rgbaMat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0), // 绿色框 2 ); } grayMat.release(); } ``` #### 3. **使用示例** ```java // 在CameraView的回调中调用 @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { Mat rgba = inputFrame.rgba(); if (faceDetector != null) { detectFaces(rgba, faceDetector); } return rgba; } ``` #### 4. **注意事项** 1. **文件复制必要性** OpenCV 的 `CascadeClassifier.load()` 需要文件系统路径,无法直接加载 `raw` 资源流,因此需先复制到内部存储[^1]。 2. **性能优化建议** - 灰度转换:检测前先转为单通道灰度图提升速度 - 尺寸限制:通过 `Size()` 参数限制最小/最大检测人脸尺寸 - 异步处理:在非UI线程执行检测避免卡顿 3. **资源更新处理** 实现 `isResourceUpdated()` 方法,通过版本号或MD5校验确保资源更新后重新复制。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值