2012-01-03 31 views
11

Tôi đang hiển thị dạng sóng trong PHP bằng cách lấy mẫu xuống bằng bộ mã hóa lame và sau đó vẽ dạng sóng từ các điểm dữ liệu kết quả. Tôi hiện đang nhận được hình ảnh như thế này:Hiển thị dạng sóng trong PHP - Cách tạo ra kết xuất được nén nhiều hơn?

enter image description here

Những gì tôi muốn làm là thay đổi mã của tôi để các dải động rõ ràng của dạng sóng thực chất là 'nén'. Để tạo ra một dạng sóng trông giống như thế này:

enter image description here

Phương trình Tôi hiện đang sử dụng để làm cho chiều cao của mỗi điểm dữ liệu như sau: -

// draw this data point 
      // relative value based on height of image being generated 
      // data values can range between 0 and 255 
      $v = (int) ($data/255 * $height); 


      // don't print flat values on the canvas if not necessary 
      if (!($v/$height == 0.5 && !$draw_flat)) 
      // draw the line on the image using the $v value and centering it vertically on the canvas 
      imageline(
       $img, 
       // x1 
       (int) ($data_point/DETAIL), 
       // y1: height of the image minus $v as a percentage of the height for the wave amplitude 
       $height * $wav - $v, 
       // x2 
       (int) ($data_point/DETAIL), 
       // y2: same as y1, but from the bottom of the image 
       $height * $wav - ($height - $v), 
       imagecolorallocate($img, $r, $g, $b) 
      );  

Với biên độ thực tế là được xác định bởi dòng đầu tiên của mã này: -

$v = (int) ($data/255 * $height); 

Thật không may là kỹ năng toán học của tôi kém nhất. Những gì tôi cần làm về cơ bản là áp dụng 'đường cong' với giá trị $ v sao cho khi số đầu vào vào phương trình thấp hơn, kết quả đầu ra cao hơn và số đầu vào tăng phương trình làm giảm khuếch đại cho đến khi đầu vào đạt 255 đầu ra cũng phải là 255. Ngoài ra đường cong phải như vậy để với đầu vào của 0 đầu ra cũng là 0.

Tôi xin lỗi nếu điều này không rõ ràng nhưng tôi đang tìm câu hỏi này rất khó để khớp với kinh nghiệm toán học hạn chế của tôi.

Có lẽ một đại diện trực quan sẽ giúp mô tả ý định của tôi: -

enter image description here

Khi giá trị của $ v là 0 hoặc 255 đầu ra của phương trình nên được chính xác đầu vào (0 hoặc 255) . Tuy nhiên, khi đầu vào là một giá trị inbetween, nó phải theo kết quả đầu ra của đường cong ở trên. (Ở trên chỉ là một bản vẽ thô để minh họa.)

EDIT:

Dựa trên Alnitiks giải pháp 'pow' chức năng bây giờ tôi đang tạo ra dạng sóng trông như thế này: -

enter image description here

Sử dụng phương trình thay thế cho biến $ v như sau: -

$v = pow($data/255.0, 0.4) * $height; 

Tôi đã thử tăng giá trị 0,4 nhưng kết quả là st bệnh không như dự định.

EDIT 2:

Theo yêu cầu ở đây là một datadump liệu của biến dữ liệu $ của tôi:

Raw Data

này được thông qua vào phương trình để trở $ v trước khi được sử dụng để vẽ dạng sóng (bạn có thể thấy những gì tôi làm với biến $ v trong mã ban đầu mà tôi đã đăng ở trên. $ height là đơn giản số pixel cao tôi đã đặt hình ảnh để hiển thị.

Dữ liệu này là danh sách giá trị được phân tách bằng dấu phẩy.Tôi hi vọng cái này giúp được. Nó xuất hiện khẳng định của bạn rằng giá trị trung bình là 128 là chính xác. Cho đến nay tôi đã không thể có được đầu của tôi xung quanh sửa chữa của bạn cho việc này. Tôi sợ nó hơi vượt quá sự hiểu biết hiện tại của tôi.

+1

+1: Tôi không chắc chắn liệu đây có phải là chủ đề đúng hay không, nhưng tôi không quan tâm ... thật thú vị! –

+0

Thực sự bạn cần tìm phương trình của đường cong đó và áp dụng hệ số nhân; đó là tất cả những điều này khi bạn giải phóng yếu tố thú vị. Và bạn có thể bỏ qua điều đó hoàn toàn và chỉ cần tạo thủ công một tra cứu các giá trị đã biết - như hakre gợi ý - nếu bạn không quan tâm đến các giá trị phân số (có vẻ như có khả năng). –

+1

Thật vậy. Tôi tự hỏi liệu điều này có nên được đăng trên trang web toán hay không. Nhưng tôi chắc chắn những câu trả lời tôi sẽ nhận được từ các bạn sẽ có nhiều hơn trong ngôn ngữ của riêng tôi hơn là một nhà toán học. :-) – gordyr

Trả lời

3

Không có kỹ năng toán học (và có thể hữu ích khi có màn hình nhanh):

Bạn có 256 giá trị có thể. Tạo một mảng chứa giá trị "năng động" cho mỗi một trong các giá trị:

$dynamic = array(
    0 => 0, 
    1 => 2, 
    ... 
); 

Đó làm, bạn có thể dễ dàng nhận được các giá trị động:

$v = (int) ($dynamic[(int) $data/255] * $height); 

Bạn có thể mất một số chính xác, nhưng nó có thể là hữu ích.


giá trị năng động tự nhiên được tạo ra bởi các hàm toán học sine và cosin, trong PHP này sin­Docs (và những người khác liên kết đó).

Bạn có thể sử dụng một vòng lặp và chức năng đó để điền trước mảng cũng và tái sử dụng các mảng, do đó bạn có giá trị trước tính:

$sine = function($v) 
{ 
    return sin($v * 0.5 * M_PI); 
}; 

$dynamic = array(); 
$base = 255; 
for ($i = 0; $i <= $base; $i++) 
{ 
    $dynamic[$i] = $i/$base; 
} 

$dynamic = array_map($sine, $dynamic); 

tôi sử dụng một hàm biến ở đây, vì vậy bạn có thể viết nhiều và có thể dễ dàng kiểm tra cái nào phù hợp với nhu cầu của bạn.

+0

Cảm ơn hakre, một mảng được xác định trước chắc chắn sẽ là giải pháp đơn giản nhất, tâm trí boggles là lý do tại sao tôi đã không nghĩ về nó bản thân mình. Nếu mọi thứ khác thất bại thì đây là phương pháp tôi sẽ thực hiện. Điều đó nói rằng tuy nhiên, tôi thà có một phương trình đơn giản làm công việc (mà cuối cùng có thể được sửa đổi đơn giản chỉ cần sự phát sinh) và như vậy tôi hiện đang khám phá đề xuất sine/cosine của bạn. Cảm ơn một lần nữa. – gordyr

+0

Đối với sin có vẻ như x đi từ i/255 * 0.5 * PI với i từ 0-255. Có thể cung cấp cho bạn đường cong của bạn. Sẽ thêm một ví dụ. – hakre

+0

Câu trả lời tuyệt vời hakre cảm ơn rất nhiều. Ví dụ của bạn thực hiện chính xác những gì tôi cần. Ngẫu nhiên tôi gần như đã có bằng cách sử dụng chức năng pow theo đề nghị của Alnitak. Tôi chắc chắn rằng phương pháp của anh ấy cũng sẽ làm việc nhưng để dành thời gian để cung cấp một ví dụ, bạn xứng đáng với câu trả lời. Rất cám ơn tất cả. :-) – gordyr

3

Bạn cần một cái gì đó tương tự như hiệu chỉnh gamma.

Đối với giá trị đầu vào x trong khoảng 0.0 -> 1.0, hãy y = pow(x, n) khi n phải nằm trong khoảng 0,2 - 0,7 (ish). Chỉ cần chọn một số cung cấp cho các đường cong mong muốn.

Khi giá trị của bạn nằm trong khoảng 0 -> 255, bạn sẽ cần chia cho 255,0, áp dụng hàm pow và sau đó nhân với 255 lần nữa, ví dụ:

$y = 255 * pow($x/255.0, 0.4); 

Công thức pow đáp ứng các tiêu chí mà 0 và 1 bản đồ cho riêng mình, và nhỏ hơn giá trị được "khuếch đại" hơn giá trị lớn hơn.

Dưới đây là một biểu đồ hiển thị đường cong gamma cho n = 1/1.6, 1/2, 1/2,4 và 1/2.8, vs đường cong sin (màu đỏ):

Gamma Curves vs Sin

càng thấp Giá trị của n, độ "nén" càng được áp dụng ở mức thấp, do đó, đường màu lam nhạt là giá trị có n = 1/2.8.

Lưu ý cách đường cong sin gần như tuyến tính trong khoảng 0 đến 0,5, do đó, hầu như không cung cấp nén ở mức độ thấp nào cả.

Nếu như tôi nghi ngờ giá trị của bạn đang thực sự tập trung vào 128, sau đó bạn cần phải sửa đổi công thức một chút:

$v = ($x - 128.0)/128.0; 
$y = 128 + 127 * sign($v) * pow(abs($v), 0.4); 

mặc dù tôi thấy rằng the PHP developers have not bao gồm một chức năng sign trong thư viện PHP.

+0

Cảm ơn Alnitak, tôi hiện đang xem xét cả hai yêu cầu của hakre và của riêng bạn. (sine/cosine & pow chức năng tương ứng.) Rất cám ơn câu trả lời của bạn và hy vọng tôi sẽ có thể đánh dấu điều này như được trả lời sớm. :-) – gordyr

+0

Đây là thông tin tuyệt vời Alnitak. Cảm ơn bạn. Nó thực sự trông giống như một giải pháp tổng thể tốt hơn. Tuy nhiên vì một lý do nào đó, tôi gặp sự cố khi tải nó để hiển thị chính xác hình ảnh. Phải có điều gì đó sai với việc tôi thực hiện câu trả lời của bạn. Tôi sẽ tiếp tục cố gắng và báo cáo lại. – gordyr

+0

@gordyr là một số giá trị âm của bạn hoặc có thể dựa trên giá trị bằng không là 128? – Alnitak

Các vấn đề liên quan