Tính điểm ngẫu nhiên (pixel) trong vòng tròn (hình ảnh)


19

Tôi có một hình ảnh chứa một vòng tròn ở một vị trí cụ thể và có đường kính cụ thể. Điều tôi cần làm là để có thể tính toán các điểm ngẫu nhiên trong vòng tròn, và sau đó thao tác các pixel cho biết các điểm tương quan với. Tôi đã có đoạn mã sau:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * ( Math.PI * 2 );
    var x = _originX + ( _radius * Math.Cos( angle ) );
    var y = _originY + ( _radius * Math.Sin( angle ) );
    return new Point( ( int )x, ( int )y );
}

Và điều đó hoạt động tốt để tìm tất cả các điểm ở chu vi của vòng tròn, nhưng tôi cần tất cả các điểm từ bất cứ đâu trong vòng tròn. Nếu điều này không có ý nghĩa hãy cho tôi biết và tôi sẽ cố hết sức để làm rõ.


Kiểm tra cập nhật.
David Gouveia

3
Câu hỏi hay theo nghĩa vô tình tạo ra phân phối có trọng số là một lỗi phổ biến.
Tim Holt

Câu trả lời:


35

Nếu bạn muốn một giải pháp đơn giản, chỉ cần chọn ngẫu nhiên bán kính:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var radius = _random.NextDouble() * _radius;
    var x = _originX + radius * Math.Cos(angle);
    var y = _originY + radius * Math.Sin(angle);
    return new Point((int)x,(int)y);
}

Tuy nhiên, điều đó dẫn đến việc các điểm của bạn tập trung nhiều hơn vào trung tâm của vòng tròn:

nhập mô tả hình ảnh ở đây

Để có được phân phối đồng đều, hãy thay đổi thuật toán sau:

var radius = Math.Sqrt(_random.NextDouble()) * _radius;

Mà sẽ cho kết quả sau:

nhập mô tả hình ảnh ở đây

Để biết thêm thông tin, hãy kiểm tra liên kết sau: MathWorld - Chọn điểm đĩa .

Và cuối cùng đây là một bản trình diễn JsFiddle đơn giản so sánh cả hai phiên bản của thuật toán.


1
Câu trả lời tuyệt vời. Chỉ cần thêm một điều: đừng quên chọn trình tạo số ngẫu nhiên :)
kevintodisco

Rất tiếc, bạn đã gặp nó - tôi không thấy bài đăng này khi tôi đăng bài của tôi. Trang web wolfram là một nguồn tài nguyên tuyệt vời cho loại điều này.
Tim Holt

1
@TimHolt xảy ra mọi lúc :)
David Gouveia

Đây có phải giả sử trung tâm vòng tròn là 0,0?
jjxtra

@PologistsoDad Trung tâm của vòng tròn sẽ là (_originX, _originY)
David Gouveia

5

KHÔNG chỉ sử dụng ngẫu nhiên r và theta! Điều này tạo ra một phân phối có trọng số với nhiều điểm hơn ở trung tâm. Trang này minh họa nó tốt ...

http://mathworld.wolfram.com/DiskPointPicking.html

Đây là phương pháp tạo phân phối không trọng số ...

var r = rand(0,1)
var theta = rand(0,360)

var x = sqrt(r) * cos(theta)
var y = sqrt(r) * sin(theta)

Rất tiếc trùng lặp câu trả lời đã chọn: P
Tim Holt

Tôi bối rối vì bạn nói không sử dụng r và theta ngẫu nhiên vì nó tạo phân phối có trọng số sau đó mã bạn hiển thị mà bạn cho rằng tạo phân phối không trọng số tạo r trong phạm vi [0,1]. Bạn có ý định căn bậc hai số ngẫu nhiên?
PeteUK

Có, làm căn bậc hai của bán kính (miễn là 0-1) làm giảm nồng độ điểm bất ngờ ở giữa. Xem liên kết Wolfram tôi đã đăng, minh họa nó và giải thích nó với toán học tốt hơn tôi có thể.
Tim Holt

Lỗi của tôi. Tôi thấy bạn làm sqrt (r) khi tính x và y.
PeteUK

4

Bạn đã được nửa chặng đường. Ngoài việc tạo một góc ngẫu nhiên, chỉ cần tạo một khoảng cách ngẫu nhiên, nhỏ hơn hoặc bằng bán kính, có trọng số để bạn có được phân phối đồng đều:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var distance = Math.Sqrt(_random.NextDouble()) * _radius;
    var x = _originX + (distance * Math.Cos(angle));
    var y = _originY + (distance * Math.Sin(angle));
    return new Point((int)x, (int)y);
}

Bây giờ bạn đang suy nghĩ với cực .

Bạn cũng có thể cân khoảng cách như vậy để tránh căn bậc hai:

var distance = _random.NextDouble() + _random.NextDouble();
distance = (distance <= 1 ? distance : 2 - distance) * _radius;

Được rồi, vì vậy chúng tôi đã đưa ra chính xác cùng một câu trả lời trong vòng vài giây khác biệt. Giờ thì sao? :)
David Gouveia

@DavidGouveia Cả hai chúng tôi đều nhận được sự ủng hộ vì cả hai đều đúng. Mọi người đều thắng! : D
Jon Purdy

Cả hai câu trả lời rất đánh giá cao (và các liên kết quá!). Người đàn ông tôi là một thằng ngốc vì bản thân tôi không nhìn thấy điều đó, -1 với tôi :( Cảm ơn một lần nữa cho cả hai bạn!
DMills

Điều này sẽ tạo ra các điểm ngẫu nhiên, nhưng chúng sẽ không được phân phối đồng đều trên đĩa, phải không? Thay vào đó họ sẽ được trọng lượng về phía trung tâm. Chỉ cần kiểm tra tôi không thiếu thứ gì.
PeteUK

1
@PeteUK: Bạn nói đúng, khoảng cách nên được tính trọng số. Hãy để tôi cập nhật.
Jon Purdy

3

Nếu hiệu suất là một vấn đề thì một giải pháp thay thế là tạo một vị trí ngẫu nhiên trong hộp có chiều rộng / chiều cao của vòng tròn của bạn và sau đó ném đi bất kỳ điểm nào không nằm trong khu vực của vòng tròn.

Ưu điểm của phương pháp này là bạn không thực hiện các chức năng cos / sin / sqrt, tùy thuộc vào nền tảng của bạn có thể tiết kiệm tốc độ lớn.

var x = _random.NextDouble();
var y = _random.NextDouble();
if (x*x + y*y < 1.0f)
{
    // we have a usable point inside a circle
    x = x * diameter - _radius + _OriginX;
    y = y * diameter - _radius + _OriginY;
    // use the point(x,y)
}

Tôi sẽ thử nó và xem nếu nó tăng tốc mọi thứ. Tôi không chắc là tôi có vấn đề về hiệu năng, nhưng dù sao tôi cũng sẽ thử điều này, cảm ơn!
DMills

0

Tôi đã thực hiện cách tiếp cận của một trong những ý kiến ​​được liệt kê và mở rộng chức năng để tạo ra một hệ thống tạo điểm hình bánh rán.

            private Vector2 CalculatePosition()
            {
                double angle = _rnd.NextDouble() * Math.PI * 2;
                double radius = InnerCircleRadius + (Math.Sqrt(_rnd.NextDouble()) * (OuterCircleRadius - InnerCircleRadius));
                double x = (_context.ScreenLayout.Width * 0.5f) + (radius * Math.Cos(angle));
                double y = (_context.ScreenLayout.Height * 0.5f) + (radius * Math.Sin(angle));
                return new Vector2((int)x, (int)y);
            }

Đó là một cách tiếp cận tương tự như đã đề cập trước đây nhưng cung cấp kết quả khác nhau. Phần bên trong của vòng tròn sẽ được để trống không có điểm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.