0

I'm making a program that's a bit like Paint light, and I've gotten to the point where I want the user to be able to select elliptical regions. My initial thought is that there must be some kind of equation that allows me to construct an ellipse based on the width and height of a rectangle. However, I've thus far not found anything quite so straight forward.

Here is my code for selecting a rectangular region when the user drags the mouse (this is located inside a MouseAdapter):

        @Override
        public void mouseDragged(MouseEvent e) {
               dragPoint = e.getPoint();
               if (selectionType.equalsIgnoreCase("Rectangle")) {
                int width = dragPoint.x - mouseAnchor.x;
                int height = dragPoint.y - mouseAnchor.y;
                subHeight = height;
                subWidth = width;
                int x = mouseAnchor.x;
                int y = mouseAnchor.y;

                if (width < 0) {
                    x = dragPoint.x;
                    width *= -1;
                }
                if (height < 0) {
                    y = dragPoint.y;
                    height *= -1;
                }
                selectionPane.setBounds(x, y, width, height);
                selectionPane.revalidate();
                repaint();
            }
  }

SelectionPane is an instance of a custom class that extends JPanel. The idea is that I want to draw a filled ellipse from the selected region, so the user can see what they've selected.

The second part of this program is where I'm also hitting some confusion. After the user makes his or her selection, I want to apply a mask to the image bits using the selected region as a guide. So I'm also working with byte arrays. How do I find which bytes are encompassed in a calculated oval based on the width, height, and origin of the sub image? Below is the code where I get the sub image based on a rectangular selection (for reference):

        @Override
        public void mouseReleased(MouseEvent e) {
            if (subWidth != 0 && subHeight != 0) {
                try {
                    //numCols * (numRows - 1) + xPos
                    int startPos = img.getWidth() * (img.getHeight() - 1) + mouseAnchor.x;//the starting position for the total byte array of the original image. The mask will start here.
                    Main.setStartingPos(startPos);
                    Main.setSubImage(img.getSubimage(mouseAnchor.x, mouseAnchor.y, Math.abs(subWidth), Math.abs(subHeight)));
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(Main.getSubImage(), "bmp", baos);
                    Main.setImageRegion(baos.toByteArray()); //sets the region bytes in the Main class

                    Main.generateImageMask();//generates the mask after everything's been calculated. 
                } catch (IOException ex) {
                    Logger.getLogger(SelectionRectangle.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

Let me know if there's any way I can make my question more clear.

İsmail Y.
  • 3,579
  • 5
  • 21
  • 29
Sarah
  • 145
  • 1
  • 14

2 Answers2

1

for axis alligned ellipse use parametric equation (centric)

x = x0 + rx*cos(a)
y = y0 + ry*sin(a)


x0,y0 is ellipse center
rx,ry are semi axises sizes (half size of your rectangle sides)
a is angle of point you want to obtain

the region is usually selected by angle interval. The angles are usually determined by a line from center (x0,y0) to actual mouse position (mx,my) or some control point as

ai = atan2(my-y0,mx-x0)

so a = < a0,a1 > where ai = { a0,a1 } are your interval angles. for full ellipse a =< 0,2*M_PI> [rad]

That is just circle approximation of angle so if you want to get more precise angle look for

Or apply circle/ellipse correction scaling ...

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
1

You can get the ellipse from the rectangle as follows:

Ellispe2D.Double el=new Ellispe2D.Double(x, y, width, height);

Then you can mask the positions covered under the ellipse as follows:

Rectangle r=el.getBounds();
for(i=0; i<r.width; i++)
  for(j=0; j<r.height; j++)
    if(el.contains(r.x+i, r.y+j)) ... do whatever with this pixel add it to a list etc

--

For pixel r.x+i, r.y+j you can get the RGB and from this the individual bytes:

int pixel=image.getRGB(r.x+i, r.y+j);
int red=(pixel&0x00ff0000)>>16, green=(pixel&0x0000ff00)>>8, blue=pixel&0x000000ff; 
gpasch
  • 2,672
  • 3
  • 10
  • 12
  • It looks like this solution might be the most straightforward, but since I'm working with an array of bytes for the image, is there a way I can extract the bytes from each pixel in the rectangle? I'm not seeing a built-in functionality for this. – Sarah Feb 02 '17 at 14:26
  • I just thought of something. It might be a bit odd, but what if I took that pixel position (r.x+i, r.y+j), and made a small sub BufferedImage from it, then extracted the image bytes from that itty bitty BufferedImage? Could that work? – Sarah Feb 02 '17 at 14:33
  • that would work as an extreme measure 1x1 image - I dont know how you will do it- but it might be unnecessary - I'll try to put a solution above – gpasch Feb 02 '17 at 17:25