我写了一个自// part of the header:
private:
const int IMAGE_HEIGHT = 800;
const float OFFSET_SCALE = 0.05f;
cv::Mat Normalizer::normalize(cv::Mat source, std::vector<cv::Rect> &rectAreas, std::vector<cv::Vec3i> &eyes, std::vector<cv::Point> &chin)
{
/*
rectAreas:
0: faceRect
1: mouth
2: brow left
3: brow right
4: nose
*/
// complete face
cv::Rect faceArea = rectAreas[0];
int offsetX = cvRound(OFFSET_SCALE * faceArea.width); // offset x of rect to be copied to the left (to get a small area around the face)
int offsetY = cvRound(OFFSET_SCALE * faceArea.height); // offset y of rect to be copied to the top (...)
int x = faceArea.x - offsetX; // for calculating if rect for copying is fully inside source, fill with black pixels otherwise
int y = faceArea.y - offsetY; // ...
int width = faceArea.width + 2 * offsetX; // width of rect to be copied
int height = faceArea.height + 2 * offsetY; // height of rect to be copied
cv::Rect offsetRect(x, y, width, height); // create rect that will be copied from source
// check if source = bounding rect
// if true: black border
int deltaX = 0, deltaY = 0;
if (x < 0) // if offsetRect is not fully in source, get difference, that will be filled with black pixels
{
offsetRect.x = 0; // if black pixels are needed, adjust offsetRect to not start at negative coordinates
deltaX = std::abs(x); // deltaX black pixels on x axis
}
if (y < 0)
{
offsetRect.y = 0;
deltaY = std::abs(y); // deltaY black pixels on y axis
}
cv::Mat output;
cv::Mat temp = cv::Mat::zeros(height + deltaY, width + deltaX, source.type());
// same size as offsetRect, starting position at deltaX:deltaY in output
cv::Rect targetRect(deltaX, deltaY, offsetRect.width, offsetRect.height);
source(offsetRect).copyTo(temp(targetRect));
// resize to X * IMAGE_HEIGHT (= 800)
float aspectRatio = (float)temp.size().height / (float)temp.size().width;
int scaledWidth = cvRound(IMAGE_HEIGHT / aspectRatio);
cv::resize(temp, output, cv::Size(scaledWidth, IMAGE_HEIGHT), 0, 0, cv::INTER_CUBIC);
temp.release();
temp = NULL;
// adjust eye centers
/*
offsetRect edge - delta output edge offsetRect edge - delta output edge
----------------------- = ------------- ######### ----------------------- = -------------
old coord - margin new coord old radius new radius
*/
for (int i = 0; i < 2; ++i)
{
eyes[i][0] = cvRound((scaledWidth * (eyes[i][0] - offsetRect.x)) / (float)(offsetRect.width - deltaX));
eyes[i][1] = cvRound((IMAGE_HEIGHT * (eyes[i][1] - offsetRect.y)) / (float)(offsetRect.height - deltaY));
eyes[i][2] = cvRound((scaledWidth * eyes[i][2]) / (float)(offsetRect.width - deltaX));
//std::cout << i << ": " << eyes[i][0] << ":" << eyes[i][1] << " " << eyes[i][2] << std::endl;
}
// adjust rect areas
rectAreas[0].x = deltaX;
rectAreas[0].y = deltaY;
rectAreas[0].width = output.size().width - deltaX;
rectAreas[0].height = output.size().height - deltaY;
/*
offsetRect edge - delta output edge
----------------------- = -------------
old edge new egde
*/
for (int i = 1; i <= 4; ++i)
{
rectAreas[i].x = cvRound((scaledWidth * (rectAreas[i].x - offsetRect.x)) / (float)(offsetRect.width - deltaX));
rectAreas[i].y = cvRound((IMAGE_HEIGHT * (rectAreas[i].y - offsetRect.y)) / (float)(offsetRect.height - deltaY));
rectAreas[i].width = cvRound((scaledWidth * rectAreas[i].width) / (float)(offsetRect.width - deltaX));
rectAreas[i].height = cvRound((IMAGE_HEIGHT * rectAreas[i].height) / (float)(offsetRect.height - deltaY));
}
// adjust chin points
for (int i = 0; i < chin.size(); i++)
{
chin[i].x = cvRound((scaledWidth * (chin[i].x - offsetRect.x)) / (float)(offsetRect.width - deltaX));
chin[i].y = cvRound((IMAGE_HEIGHT * (chin[i].y - offsetRect.y)) / (float)(offsetRect.height - deltaY));
}
return output;
}
扩展的自定义文本视图(实际上是什么类型的视图无关紧要)。我在XML文档中向此视图添加了填充并读取这些填充并将其传递给View
以应用这些填充。在我的super
和onDraw
中,我也考虑了这些填充,一切正常。
EXCEPT ,如果我通过方法onMeasure
滚动此视图,则填充不再有效。通过说不再有效,我的意思是View.scrollTo()
上绘制的内容不尊重视图的填充,如下图所示:
我想知道是否有任何解决方法?(PS:不要告诉我使用canvas
而不是自己制作。我这样做是因为某些原因,我想要的唯一问题解决这里只是填充的东西,而不是一些很棒的替代品,谢谢!)
编辑: 我的xml
TextView
并在我的构造函数中:
<com.example.custom.MyTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text_area"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/text_bg"
android:padding="10dp"/>
在我的onMeasure中:
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// by calling super, the super class will take care of the paddings
// internal, and after this, I just have to get the paddings by
// getPaddingTop(),getPaddingLeft(),getPeddingRight(),getPaddingBottom() etc.
}
在我的onDraw中:
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
......
setMeasuredDimension(getPaddingLeft()+contentWidth+getPaddingRight()
,getPaddingTop()+contentHeight+getPaddingBottom());
//whereas the contentWidth and contentHeight is determined by the widthMeasureSpec
// and heightMeasureSpec and some certain logic inside the view.
// I don't think this will cause the view's content to exceed the conten area
}