Соответствие между координатами ImageView и растровыми пикселями – Android

В моем приложении я хочу, чтобы пользователь мог выбрать некоторый контент изображения, содержащегося внутри ImageView .

Чтобы выбрать контент, я подклассифицировал класс ImageView чтобы он реализовал OnTouchListener чтобы нарисовать над ним прямоугольник с границами, определенными пользователем.

Вот пример результата чертежа (чтобы иметь представление о том, как он работает, вы можете думать об этом, как при щелчке мышью на рабочем столе и перетаскивании мышью):

Введите описание изображения здесь

Теперь мне нужно определить, какие пиксели Bitmap изображения соответствуют выбранной части. Легко определить, какие точки ImageView принадлежат прямоугольнику, но я не знаю, как получить соответствующие пиксели, поскольку ImageView имеет другое соотношение сторон, чем исходное изображение.

Я следовал описанному здесь особому подходу, но и здесь , но не полностью удовлетворен, потому что, по моему мнению, сделанная переписка составляет 1 на 1 между пикселями и точками на ImageView и не дает мне всех соответствующих пикселей на исходном изображении на Выбранной области.

Вызов hoveredRect прямоугольник в ImageView внутри которого находятся точки:

 class Point { float x, y; @Override public String toString() { return x + ", " + y; } } Vector<Point> pointsInRect = new Vector<Point>(); for( int x = hoveredRect.left; x <= hoveredRect.right; x++ ){ for( int y = hoveredRect.top; y <= hoveredRect.bottom; y++ ){ Point pointInRect = new Point(); pointInRect.x = x; pointInRect.y = y; pointsInRect.add(pointInRect); } } 

Как я могу получить Vector<Pixels> pixelsInImage содержащий соответствующие пиксели Bitmap ?


ДОПОЛНИТЕЛЬНЫЕ ПОЯСНЕНИЯ

Я немного объясню контекст моей проблемы:

Мне нужно сделать некоторую обработку изображения на выбранной части и хочу быть уверенным, что все пиксели в прямоугольнике будут обработаны.

Обработка изображений будет выполняться на сервере, но он должен точно знать, какие пиксели обрабатывать. Сервер работает с изображением с реальными размерами, приложение для Android просто сообщает, какие пиксели обрабатываются на сервере, передавая вектор, содержащий координаты пикселя

И почему мне не нравятся решения, предложенные в ссылках выше:

Ответы, полученные с помощью преобразований координат с 1 по 1 моды. Этот подход явно недействителен для моей задачи, так как область, скажем, 50 точек в ImageView определенного размера на экране, не может соответствовать области с таким же количеством пикселей в реальном изображении, но должна учитывать различное соотношение сторон ,

В качестве примера это область, которую следует выбрать, если изображение меньше, чем ImageView показанное в приложении:

Введите описание изображения здесь

Solutions Collecting From Web of "Соответствие между координатами ImageView и растровыми пикселями – Android"

Маттео,

Похоже, это больше вопрос о том, сколько ошибок вы можете (субъективно) терпеть, в каких пикселях вы отправляете на сервер. Факт остается фактом, что для любого соотношения сторон, которое не выходит на красивое аккуратное целое число, вам нужно решить, в каком направлении «нажать» ваш поле выбора.

Решения, с которыми вы связаны, – это отличные решения. Вы должны спросить себя: узнает ли пользователь, будет ли обработанное изображение одним пикселем в окне выбора, показанном на экране? Думаю, наверное, нет. Я не могу себе представить, что пользователь будет иметь такую ​​точность пикселей, когда выберете прямоугольник с большим толстым пальцем на сенсорном экране: D

Поскольку это так, я бы просто дал floor() которое возникает, когда бросание в целое число позаботится о том, какие пиксели вы переходите на сервер.

Давайте посмотрим на пример.

Определим ширину и высоту нашего ImageView и Bitmap:

 ImageViewWidth = 400, ImageViewHeight = 150 BitmapWidth = 176, BitmapHeight = 65 

Тогда пропорции, которые вы будете использовать для преобразования вашего окна выбора между ними, будут следующими:

 WidthRatio = BitmapWidth / ImageViewWidth = 175 / 400 = 0.44 HeightRatio = BitmapHeight / ImageViewHeight = 65 / 150 = 0.44 

Некоторые хорошие уродливые номера. Независимо от того, какой пиксель я включен в ImageView, будет соответствовать пикселю в Bitmap, например:

 BitmapPixelX = ImageViewPixelX * WidthRatio BitmapPixelY = ImageViewPixelY * HeightRatio 

Теперь я поместил это растровое изображение на экране в свой ImageView, чтобы пользователь мог выбрать прямоугольник, и пользователь выбирает прямоугольник с левыми и нижними правыми координатами в ImageView как таковой:

 RectTopLeftX = 271, RectTopLeftY = 19 RectBottomRightX = 313, RectBottomRightY = 42 

Как определить, какие пиксели в битовой карте соответствуют? Легко. Соотношения, которые мы определили ранее. Давайте посмотрим только на верхние левые координаты.

 RectTopLeftX * WidthRatio = 271 * .44 = 119.24 RectTopLeftY * HeightRatio = 19 * .44 = 8.36 

Для RectTopLeftX мы получаем значение BitmapPixelX 119, а затем примерно четверть пути в пиксель. Ну, если мы будем использовать это значение и соответствующее значение BitmapPixelY 8.36, мы будем отправлять пиксель (119, 8) на сервер для обработки. Если бы мы ceil() эти значения, мы будем посылать пиксель (120, 9) на сервер для обработки. Это та часть, которая полностью зависит от вас.

Вы будете (почти) всегда приземляться в некоторой частичной части пикселя. Вы отправляете пиксель, в который вы попадаете, или тот, который рядом с ним, является вашим вызовом. Я бы сказал, что это будет совершенно незаметно для вашего пользователя, и, чтобы повторить, просто дайте floor() которое возникает, когда кастинг в целое позаботится об этом.

Надеюсь, это поможет!

[РЕДАКТИРОВАТЬ]

Повторяя вопрос еще медленнее, я думаю, что лучше понять, о чем вы спрашиваете / путаете. Я проиллюстрирую мой пример выше.

Вы говорите, что в Bitmap есть 176 пикселей и 400 пикселей в ImageView. Поэтому сопоставление от одного к другому не равно 1: 1, и это вызовет проблемы при определении того, какие пиксели вытащить для обработки.

Но это не так! Когда вы конвертируете координаты границ прямоугольника в ImageView в координаты в Bitmap, вы просто даете диапазон пикселей для перебора в Bitmap. Это не описание того, как каждый отдельный пиксель в ImageView сопоставляется с соответствующим пикселем в растровом изображении.

Надеюсь, это облегчит мое замешательство в твоей путанице.

Это разрешимо с очень простой математикой, ваш прямоугольник имеет 4 точки p1, p2, p3, p4, с координатами x, y, относительно ImageView.

Вы также знаете размеры исходного изображения.

Теперь, если p1.x, например, равно 50, в ImageView шириной 200 px, вы получаете отношение 50/200 = 0,25

Если ваше исходное изображение имеет ширину 100 пикселей, ваша точка p1.x будет располагаться со 100 * 0.25 = 25 px

Можно выразить:

50 -> 200

? -> 100

И рассчитано:

? = 100 * 50/200

Вы делаете это для каждой точки, для каждого измерения x, y, а затем вы получаете 4 точки прямоугольника в исходном изображении.

Теперь, если вы повторяете эти расчетные точки, вы должны получить пиксели прямоугольника в исходном изображении.

Здесь я предполагаю, что вы поместили что-то внутри своего изображения. Сделайте это внутри onCreate:

 ImageView image=(ImageView) findViewById(R.id.imageView1); TextView coordinates=(TextView) findViewById(R.id.textView1); bitmap = ((BitmapDrawable)Map.getDrawable()).getBitmap(); 

И это внутри onTouch:

 coordinates.setText("Touch coordinates:"+String.valueOf(event.getX())+"x"+String.valueOf(event.getY())); int pixel = bitmap.getPixel((int)event.getX(), (int)event.getY()); 

Теперь у вас есть конкретный пиксель, который вы хотите.