В моем приложении у меня есть ImageView, который я превратил в Bitmap для редактирования. Мне нужно определить, какие пиксели в ImageView были затронуты пользователем. Кроме того, если пользователь рисует линию пальцем, мне нужно знать все пиксели, которые были затронуты, чтобы их изменить. Как определить, какие пиксели были затронуты?Как найти все пиксели, затронутые представлением изображения?
ответ
Ok Jonah, вот несколько направлений для вас.
Я предполагаю, что вы хотите, чтобы эффект смешивания быстро реагировал на ввод пользователя, поэтому прежде всего вам лучше перейти на пользовательский SurfaceView вместо ImageView, потому что он более подходит для рисования анимаций с высокой частотой кадров, необходимых для 2D-игр и анимаций. Я настоятельно рекомендую вам прочитать this guide; уделяя особое внимание части об использовании SurfaceView
, прежде чем идти дальше. Вам в основном нужно создать класс, который расширяет SurfaceView
и реализует SurfaceHolder.Callback
. Затем это представление будет отвечать за прослушивание событий пользовательского касания и визуализации кадров для анимации эффекта смешивания.
Взгляните на следующий код в качестве ссылки:
public class MainView extends SurfaceView implements SurfaceHolder.Callback {
public MainView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this); // Register this view as a surface change listener
setFocusable(true); // make sure we get key events
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
// Check if the touch pointer is the one you want
if (event.getPointerId(event.getActionIndex()) == 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// User touched screen...
case MotionEvent.ACTION_CANCEL:
// User dragged his finger out of the view bounds...
case MotionEvent.ACTION_UP:
// User raised his finger...
case MotionEvent.ACTION_MOVE:
// User dragged his finger...
// Update the blending effect bitmap here and trigger a frame redraw,
// if you don't already have an animation thread to do it for you.
return true;
}
return false;
}
/*
* Callback invoked when the Surface has been created and is ready to be
* used.
*/
public void surfaceCreated(SurfaceHolder holder) {
// You need to wait for this call back before attempting to draw
}
/*
* Callback invoked when the Surface has been destroyed and must no longer
* be touched. WARNING: after this method returns, the Surface/Canvas must
* never be touched again!
*/
public void surfaceDestroyed(SurfaceHolder holder) {
// You shouldn't draw to this surface after this method has been called
}
}
Затем используйте его на макет вашего «рисунок» деятельности, как это:
<com.xxx.yyy.MainView
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Чтобы привлечь к этой поверхности вам нужен следующий код:
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (c != null)
c.drawBitmap(blendingImage, 0, 0, null); // Render blending effect
}
} catch (Exception e) {
Log.e("SurfaceView", "Error drawing frame", e);
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
Полностью функциональный пример нецелесообразно вставлять в ответ, поэтому я рекомендую вам загрузить Lunar Lander sample game from Google для полного рабочего примера. Обратите внимание, однако, что вам не понадобится нить игровой анимации (хотя это не повредит ей), как и тот, который был закодирован в примере Lunar Lander, если вам нужен только эффект смешивания. Цель этого потока - создать игровой цикл, в котором игровые кадры постоянно генерируются для анимации объектов, которые могут или не могут зависеть от ввода пользователя. В вашем случае все, что вам нужно, это вызвать перерисовку кадров после обработки каждого события касания.
EDIT: Следующий код является исправлением, чтобы получить код, который вы предоставили в комментариях, работая.
Вот изменения в MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// put pics from drawables to Bitmaps
Resources res = getResources();
BitmapDrawable bd1 = (BitmapDrawable) res.getDrawable(R.drawable.pic1);
// FIX: This block makes `operation` a mutable bitmap version of the loaded resource
// This is required because immutable bitmaps can't be changed
Bitmap tmp = bd1.getBitmap();
operation = Bitmap.createBitmap(tmp.getWidth(), tmp.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(operation);
Paint paint = new Paint();
c.drawBitmap(tmp, 0f, 0f, paint);
BitmapDrawable bd2 = (BitmapDrawable) res.getDrawable(R.drawable.pic2);
bmp = bd2.getBitmap();
myView = new MainView(this, operation, bmp);
FrameLayout preview = (FrameLayout) findViewById(R.id.preview);
preview.addView(myView);
}
...
Вот изменения в классе MainView:
public class MainView extends SurfaceView implements Callback {
private SurfaceHolder holder;
private Bitmap operation;
private Bitmap bmp2;
private boolean surfaceReady;
// took out AttributeSet attrs
public MainView(Context context, Bitmap operation, Bitmap bmp2) {
super(context);
this.operation = operation;
this.bmp2 = bmp2;
holder = getHolder(); // Fix: proper reference the instance variable
holder.addCallback(this); // Register this view as a surface change
// listener
setFocusable(true); // make sure we get key events
}
// Added so the blending operation is made in one place so it can be more easily upgraded
private void blend(int x, int y) {
if (x >= 0 && y >= 0 && x < bmp2.getWidth() && x < operation.getWidth() && y < bmp2.getHeight() && y < operation.getHeight())
operation.setPixel(x, y, bmp2.getPixel(x, y));
}
// Added so the drawing is now made in one place
private void drawOverlays() {
Canvas c = null;
try {
c = holder.lockCanvas(null);
synchronized (holder) {
if (c != null)
c.drawBitmap(operation, 0, 0, null); // Render blending
// effect
}
} catch (Exception e) {
Log.e("SurfaceView", "Error drawing frame", e);
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (!surfaceReady) // No attempt to blend or draw while surface isn't ready
return false;
// Check if the touch pointer is the one you want
if (event.getPointerId(event.getActionIndex()) == 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// User touched screen. Falls through ACTION_MOVE once there is no break
case MotionEvent.ACTION_MOVE:
// User dragged his finger...
blend((int) event.getX(), (int) event.getY());
}
// Update the blending effect bitmap here and trigger a frame
// redraw,
// if you don't already have an animation thread to do it for you.
drawOverlays();
return true;
}
return false;
}
/*
* Callback invoked when the Surface has been created and is ready to be
* used.
*/
public void surfaceCreated(SurfaceHolder holder) {
surfaceReady = true;
drawOverlays();
}
/*
* Callback invoked when the Surface has been destroyed and must no longer
* be touched. WARNING: after this method returns, the Surface/Canvas must
* never be touched again!
*/
public void surfaceDestroyed(SurfaceHolder holder) {
// You shouldn't draw to this surface after this method has been called
surfaceReady = false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
}
Этот код работает для меня. Я просто надеюсь, что ничего не забыл =)
Сообщите мне, если у вас все еще есть проблемы, хорошо?
Спасибо большое! Но как установить обновленное растровое изображение на Surface View? И что я вкладываю в OnActionUp? –
Вы не «устанавливаете» растровое изображение, как если бы это был ImageView. Вы захватываете объект Canvas и рисуете растровое изображение на нем (как показано в последнем блоке кода). Теперь о событиях касания «MotionEvent.ACTION_UP» обычно важно сообщить вам, что «жест», начатый 'MotionEvent.ACTION_DOWN', закончился. Это может быть или не быть важно для вас. Скажем, например, у вас есть игра, в которой пользователь должен перетаскивать фигуры на доске. 'MotionEvent.ACTION_UP' - это событие, в котором говорится, что пользователь только что закончил перетаскивание, поэтому пришло время разместить кусок в ближайшей действующей доске. – ulix
Я когда через все шаги, но приложение все еще имеет ошибки. Вот ссылки на мою главную учетную запись: https://docs.google.com/document/d/16KfcnpjVPUbHeM3VlfBX55FFbPFHJAPDeRqJl3r8Tyo/pub и MainView https://docs.google.com/document/d/1x15Mn-dl2BNx__EORl94e4XEwwLfRsciG7GUQP331YU/pub Что я делаю неправильно ? –
Так что ответ на этот вопрос заключается в том, что вам нужно быть немного умным, но это действительно не должно быть так плохо. Вместо того, чтобы размещать весь код, чтобы делать то, что вы хотите сделать, я дам вам ссылку here и объяснение.
Таким образом, управляя событиями касания приложения, вы можете определить средние координаты события касания. Используя эту информацию, вы можете определить центр всех затронутых пикселей и продолжить отслеживать это, когда линия рисуется пальцем. Для отслеживания прямой линии используйте
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
Оговорки, необходимые для определения начала и конца строки. Если вы хотите, чтобы отслеживать линию, которая не является прямым и нарисовано, вы будете нуждаться немного больше отслеживания с помощью
case MotionEvent.ACTION_MOVE:
и что вы должны получить достаточно начать. Вам может понадобиться немного логики, чтобы справиться с тем, что вы будете рисовать очень тонкую линию, и я подозреваю, что это совсем не то, что вы собираетесь делать. Может быть, это правда. В любом случае это должно быть хорошим местом для начала работы.
EDIT
Что касается вашего первого комментария, here это ссылка, которую вы можете использовать для примера. Однако я должен сделать небольшой отказ от ответственности. Чтобы все части могли работать вместе правильно, сначала это может показаться простым. Уверяю вас, что это один из самых простых примеров и разбивает учебник на разделы.
За то, что вы хотели бы сделать, я думаю, что вы хотите, чтобы обратить особое внимание на раздел 2 (не следует путать с шагом 2):
не2. Facilitate Drawing
Я предлагаю это потому, что он показывает различные способы для использования информации из TouchEvent. Предметы, включенные в раздел 1, немного объяснят среду для настройки отображения захваченных данных TouchEvent, в то время как раздел 3 в основном касается эстетики. Это не может напрямую ответить на ваш вопрос, но я подозреваю, что он доставит вас туда, где вам нужно.
Счастливое кодирование! Оставьте комментарий, если у вас есть какие-либо вопросы.
Можете ли вы отправить ссылку простого рабочего кода, чтобы я мог начать с места, так как я довольно потерян. Большое спасибо! –
- 1. Получить все пиксели изображения [Wand]
- 2. Попытка перерисовать все пиксели изображения рекурсивно
- 3. Найти таблицы, затронутые SQL-инъекцией
- 4. Найти все таблицы, связанные с представлением
- 5. Как повернуть пиксели растрового изображения
- 6. Как пропустить все пиксели изображения в телефоне Windows 8 app
- 7. Как перебирать все пиксели UIImage?
- 8. Как найти все пиксели на некотором расстоянии от заданного пикселя?
- 9. Как изменить все пиксели JPEG на Android?
- 10. Как найти соседние пиксели и его координаты
- 11. OpenCV: как найти пиксели внутри полигона?
- 12. сделать все цветные пиксели непрозрачных
- 13. список GitPython все файлы, затронутые определенное обязательство
- 14. jQuery - скрыть родителя, если все затронутые дети
- 15. Как изменить все пиксели в заданном прямоугольнике
- 16. Overriding ModelForm.save не обновляет все затронутые поля
- 17. Как печатать пиксели изображения в виде матрицы?
- 18. Измените все белые пиксели изображения прозрачным в OpenCV C++
- 19. Найти все пиксели на одной строке в Java
- 20. Найти все пиксели заданного радиуса от точки, ограниченной внутри дуги
- 21. ImageJ, возвращающий все пиксели в формате rgb из фрагмента изображения
- 22. Как изменить пиксели ImageIcon на белые пиксели?
- 23. imadjust превращает все пиксели на белом
- 24. Твердые раскрасить видимые пиксели изображения
- 25. Как поменять пиксели изображения в случайном порядке?
- 26. получить пиксели изображения в массив
- 27. Resample пиксели изображения в Python
- 28. Найти/перечислить все не белые пиксели в CGImage?
- 29. Does JSoup найти ВСЕ изображения
- 30. C# getPixel не выделяет все пиксели
Не могли бы вы подробнее рассказать о том, что вы подразумеваете под «необходимостью определять, какие пиксели на ImageView были затронуты пользователем»? Похоже, вы хотите создать какой-то инструмент для редактирования изображений, в котором пользователю разрешено «рисовать» путь пальцем по растровому изображению. Если это так, вы пытались просто зарегистрировать прикосновение и перетащить слушателей для своего вида и разобраться с координатами событий? – ulix
Я начинающий программист, поэтому я действительно не знал, с чего начать. В моем приложении я показываю один рисунок, и когда пользователь прикасается к рис., Эти пиксели превращаются в соответствующие пиксели на другой рис. Это создает эффект смешивания. Я знаю, как смешивать фотографии, но не знаю, как заставить слушателей прикоснуться. –